home *** CD-ROM | disk | FTP | other *** search
/ HPAVC / HPAVC CD-ROM.iso / CHFLZ100.ZIP / CHIEFLZ.PAS < prev    next >
Pascal/Delphi Source File  |  1996-09-05  |  111KB  |  3,672 lines

  1. {
  2.    CHIEFLZ UNIT/DLL, by Dr A Olowofoyeku (the African Chief);
  3.    internet: laa12@cc.keele.ac.uk
  4.    http://ourworld.compuserve.com/homepages/African_Chief/chief.htm
  5.  
  6.    Version 1.00.
  7.  
  8.    USES the original LZSSUNIT source, as amended by the Chief,
  9.    and Chris J Rankin. Ported to Win32 (Delphi 2.0) by Chris Rankin.
  10.  
  11.    // -----------------------------------------------------------//
  12.     * 16-bit ASM functions converted to 32-bit ASM by Chris J Rankin
  13.     * Win32 (Delphi 2.0) code: added by Chris J Rankin
  14.  
  15.   Package assembled together: 5th September 1996.
  16.  
  17.   The routines in this package are already being used in some famous
  18.   programs!
  19. }
  20.  
  21.  
  22.  
  23. {----------------------------------------------------------------------}
  24. {to compile to a DLL in Delphi you need to rename this with the
  25. extension .DPR}
  26.  
  27. {$I LZDefine.inc}   {// defines various things, including "aDLL" //}
  28.  
  29. {$ifDef aDLL}
  30.  Library ChiefLZ;
  31.  
  32.  Uses
  33.  {$ifdef Win32}
  34.    ShareMem,    // Because the library exports functions that have
  35.                 // long-string results/parameters, we need to use
  36.                 // the ShareMem unit. All apps that use this library
  37.                 // *must also use ShareMem* - Put DelphiMM.dll on the
  38.                 // Path too ...
  39.    Windows,
  40.    LZSS32,
  41.    LZ_Const,
  42.    LZ_DLL,
  43.  {$else Win32}
  44.    LZSS16,
  45.  {$ifdef Windows}
  46.  {$ifdef DPMI}
  47.    WinAPI,
  48.  {$else DPMI}
  49.    WinProcs,
  50.  {$endif DPMI}
  51.  {$endif Windows}
  52.  {$endif Win32}
  53.  {$ifDef Delphi}
  54.    SysUtils,
  55.  {$else Delphi}
  56.    WinDos,
  57.    Strings,
  58.  {$endif Delphi}
  59.    ChfTypes,
  60.    ChfUtils;
  61.  
  62. {$else aDLL}
  63.  Unit ChiefLZ;
  64. {$endif aDLL}
  65.  
  66. {------------------------------------------------------------}
  67.  
  68. {$ifNDef aDLL}
  69. interface
  70. uses
  71. {$ifdef Delphi}
  72.   SysUtils,
  73. {$endif}
  74.   ChfTypes;
  75. {$endif aDLL}
  76.  
  77.  Const ChiefLZVersionNumber = 100; { version 1.00 }
  78.  
  79. {$ifdef Win32} Var
  80. {$else}        Const
  81. {$endif} MyLZMarker:Char = '~'; {last char in filenames created automatically}
  82.  
  83. {////////////////////////////////////////////////////}
  84. {////////////////////////////////////////////////////}
  85. {////////////////////////////////////////////////////}
  86.   {Pascal object encapsulating the functionality of
  87.   this unit - CANNOT BE EXPORTED BY DLL}
  88. {////////////////////////////////////////////////////}
  89. {////////////////////////////////////////////////////}
  90. {$ifndef aDLL}
  91.  
  92. Type
  93. LZObj={$ifdef Delphi}Class{$else Delphi}Object{$Endif Delphi}
  94.    Constructor {$ifdef Delphi} Create
  95.                {$else}         Init
  96.                {$endif}(Const InfName, OutFName:String);
  97.    {you can init with source and target file names,
  98.    or with blanks - so set the source and target file names
  99.    later
  100.    }
  101.  
  102.    Destructor {$ifdef Delphi} Destroy; override
  103.               {$else}         Done;    virtual
  104.               {$endif};
  105.  
  106.    {$ifndef Delphi}
  107.    Procedure SetInputName(Const aName: String);
  108.    {set source file name; absolutely necessary}
  109.  
  110.    Procedure SetOutputName(Const aName: String);
  111.    {set target file name = if empty, then a default one
  112.    will be used}
  113.  
  114.    Procedure SetReportProc(const aProc: TLZReportProc);
  115.    {point to procedure to report progress}
  116.  
  117.    Procedure SetQuestionProc(const aProc: TLZQuestionFunc);
  118.    {point to function to ask question if the target file exists
  119.    already - if nothing is set, then existing target files will
  120.    be overwritten automatically}
  121.    {$endif}
  122.  
  123.    Function Compress: Longint; virtual;
  124.    {compress the source file >> target file }
  125.  
  126.    Function Decompress: Longint; virtual;
  127.    {decompress the source file >> target file}
  128.  
  129.  private
  130.  {$ifdef Delphi}
  131.    FQuestionProc: TLZQuestionFunc;
  132.    FReportProc  : TLZReportProc;
  133.    fInputName,
  134.    fOutputName  : StrType;
  135.    function GetIsInited: boolean;
  136.  public
  137.    property QuestionProc: TLZQuestionFunc read FQuestionProc
  138.                                           write FQuestionProc;
  139.    property ReportProc: TLZReportProc read FReportProc
  140.                                       write FReportProc;
  141.    property IsInited:   boolean read GetIsInited;
  142.    property InputName:  StrType read FInputName write FInputName;
  143.    property OutputName: StrType read FOutputName write FOutputName;
  144.  {$else Delphi}
  145.    IsInited    : boolean;
  146.    QuestionProc: TLZQuestionFunc;
  147.    ReportProc  : TLZReportProc;
  148.    InputName,
  149.    OutputName  : StrType;
  150.  {$endif Delphi}
  151. End{LZOBJ};
  152. {$endif aDLL}
  153. {////////////////////////////////////////////////////}
  154. {////////////////////////////////////////////////////}
  155.  
  156. {exported INTERFACE functions}
  157. {$ifNDef aDLL}
  158.  
  159. Function LZCompress(const {$ifdef Win32} Source, Dest:   string
  160.                           {$else}        aSource, aDest: PChar
  161.                           {$endif};
  162.                     LZQuestion: TLZQuestionFunc;
  163.                     aProc:      TLZReportProc):LongInt;
  164. { This Function is used for compression.
  165.   Source     = Source file name
  166.   Dest       = target file name
  167.   LZQuestion = procedural type to ask for overwrite permission
  168.   aProc      = procedural type to return progress information
  169. }
  170.  
  171.  
  172. Function LZDecompress({$ifdef Win32} Source, Dest:  string
  173.                       {$else} const aSource, aDest: PChar
  174.                       {$endif};
  175.                       LZQuestion: TLZQuestionFunc;
  176.                       aProc:      TLZReportProc):LongInt;
  177. { This functione is used for decompression.
  178.   Source     = Source file name
  179.   Dest       = target file name
  180.   LZQuestion = procedural type to ask for overwrite permission
  181.   aProc      = procedural type to return progress information
  182. }
  183.  
  184. Function IsChiefLZFile(const fName: {$ifdef Win32} string
  185.                                     {$else}        PChar
  186.                                     {$endif} ): boolean;
  187. {is this an LZ file compressed with this unit?}
  188.  
  189. Function LZArchive(const fSpec, ArchName: {$ifdef Win32} string
  190.                                           {$else}        PChar
  191.                                           {$endif};
  192.                    LZRecurseDirs: TLZRecurse;
  193.                    aProc:         TLZReportProc): LongInt;
  194. {archive all the files matching "fSpec" into archive "ArchName";
  195.  fSpec = a filespec (e.g., "*.PAS", or a filename containing a list
  196.  of files to be archived - in which case, use "/F=<listfilename>" as
  197.  the fSpec.
  198.  LZRecurseDirs = whether to recurse into subdirectories for matching
  199.  files
  200. }
  201.  
  202. Function LZDearchive(ArchName: {$ifdef Win32} string
  203.                                {$else}        PChar
  204.                                {$endif};
  205.                     {$ifdef Win32} DefDir: string
  206.                     {$else} const aDefDir: PChar
  207.                     {$endif};
  208.                      LZQuestion: TLZQuestionFunc;
  209.                      aProc:      TLZReportProc;
  210.                      aRename:    TLZRenameFunc): LongInt;
  211. {De-Arc a ChiefLZ archive}
  212.  
  213. Function IsChiefLZArchive(const fName: {$ifdef Win32} string
  214.                                        {$else}        PChar
  215.                                        {$endif} ): boolean;
  216. {is this an LZ archive file compressed with this unit?}
  217.  
  218. Function GetChiefLZFileName{$ifdef Win32}(const fName: string): string;
  219.                            {$else} (fName, Dest: PChar): boolean;
  220.                            {$endif}
  221. {if LZ file, then return name (in dest, if not Win32) - else return
  222.  fname (in dest, if not Win32) }
  223.  
  224. Function GetChiefLZFileSize(fName: {$ifdef Win32} string
  225.                                    {$else}        PChar
  226.                                    {$endif}): LongInt;
  227. {if LZ file then return uncompressed size - else
  228.  return actual filesize. On error, Win32 throws exception; Win16 returns -1 }
  229.  
  230. function GetChiefLZArchiveInfo(const ArchName: {$ifdef Win32} string
  231.                                                {$else Win32}  PChar
  232.                                                {$endif Win32};
  233.                                var Header: TChiefLZArchiveHeader): boolean;
  234. { if LZ-Archive then this function returns True, with the header info
  235.   in Header. Otherwise the function returns False }
  236.  
  237. Function GetChiefLZArchiveSize(const ArchName: {$ifdef Win32} string
  238.                                                {$else Win32}  PChar
  239.                                                {$endif Win32}): LongInt;
  240. {$ifdef aDLL} {$ifdef Win32} stdcall
  241.               {$else Win32}  export
  242.               {$endif Win32};
  243. {$endif aDLL}
  244. { If ArchName is LZArchive, returns sum of uncompressed file-sizes in archive.
  245.   If not LZArchive then returns size of file ArchName } 
  246.  
  247. Function LZCompressEx(const {$ifdef Win32} Name:  string
  248.                             {$else}        aName: PChar
  249.                             {$endif};
  250.                       ReplaceQuestion: TLZQuestionFunc;
  251.                       aProc:           TLZReportProc): LongInt;
  252. {compress the file aName, and use the filename,
  253.  with the last character replaced by a '~' as the output file
  254.  If target file exists, and autoreplace=false then the
  255.  function exits and returns -100 else the target file
  256.  will be overwritten
  257. }
  258.  
  259. Function LZDecompressEx({$ifdef Win32} Name: string
  260.                         {$else}       aName: PChar
  261.                         {$endif};
  262.                         ReplaceQuestion: TLZQuestionFunc;
  263.                         aProc:           TLZReportProc): LongInt;
  264. {decompress the file aName, obtaining the output name from
  265. the header automatically
  266. If target file exists, and autoreplace=false then the
  267. function exits and returns -100 else the target file
  268. will be overwritten
  269. }
  270.  
  271. function GetFullLZName(Const X    : TChiefLZArchiveHeader;
  272.                              Index: Integer): String;
  273. {for internal use}
  274.  
  275. {$endif aDLL}
  276.  
  277. {////////////////////////////////////////////////////}
  278.  
  279. {$ifNDef aDLL}
  280. implementation
  281.  
  282. uses
  283.   ChfUtils,
  284. {$ifdef Win32}
  285.   LZSS32, Windows, LZ_Const
  286. {$else Win32}
  287.   LZSS16,           { All 16-bit code }
  288. {$ifdef Windows}
  289.   WinProcs          { Win16 }
  290. {$ifndef Delphi}
  291.  ,WinDos, Strings   { TPW / BPW }
  292. {$endif Delphi}
  293. {$else Windows}
  294.   Dos, Strings      { TP / BP }
  295. {$endif Windows}
  296. {$endif Win32};
  297.  
  298. {$endif aDLL}
  299.  
  300. {$ifdef Win32}
  301. {
  302.   These constants taken from SysUtils.inc ...
  303. }
  304. {$ifdef Ver90}
  305. const SInOutError   = 65416;
  306. const SFileNotFound = 65417;
  307. const SEndOfFile    = 65421;
  308. {$else Ver90}
  309.   These constants may have changed; Check SysUtils.inc ... or scan
  310.   the String Resource Table from 0-65535 looking for keywords ...
  311. {$endif Ver90}
  312. {$endif Win32}
  313.  
  314. const ChiefLZSig = 'aChiefM#';
  315. const NulFileDate = 2162688;   { 01/01/1980 12:00a }
  316.  
  317. {////////////////////////////////////////////////////}
  318.  
  319. {//// my header to identify LZ file///}
  320. Type
  321. PLZHeader = ^TLZHeader;
  322. TLZHeader = Packed Record
  323.  fName: TLZFileStr;   {filename}
  324.  uSize: LongInt;      {uncompressed size}
  325.  cSize: LongInt;      {compressed size}
  326.  fTime: LongInt;      {time/date stamp}
  327.  Version: TLZVerStr;
  328.  Signature: String[8];  {the identification header}
  329. end;
  330.  
  331. Type
  332. TLZBigFileRec= packed Record
  333. {is it a directory}
  334.        IsBigDir: Boolean;
  335. {its directory ID}
  336.        BigDirID: Word;
  337. {its parent directory ID}
  338.        BigParentDir: Word;
  339. {is it compressed?}
  340.        BigCompressed: Boolean;
  341. {any version information?}
  342.        BigFileVersion: TLZVerStr;
  343. {compressed sizes}
  344.        BigSizes: LongInt;
  345. {uncompressed sizes}
  346.        uBigSizes:LongInt;
  347. {date/time stamps}
  348.        BigTimes: LongInt;
  349. {file names}
  350.        BigNames: TLZPathStr
  351. end;
  352.  
  353. PLZArchiveFiles = ^TLZArchiveFiles;
  354. TLZArchiveFiles = Array[1..MaxChiefLZArchiveSize] of TLZBigFileRec;
  355.  
  356. Const
  357. MySigStr = #4+^M+'ChfLZ'+#5#6#8;
  358. MyLZSignature :String[Length(MySigStr)]= MySigStr;
  359.  
  360. Const
  361. CopyBufSize=32000;
  362.  
  363. Type
  364. PBufType=^TBufType;
  365. TBufType=array[1..CopyBufSize] of byte;
  366.  
  367. {////////////////////////////////////////////////////}
  368.  
  369. Type  {don't want to use collections because of other versions of TPascal}
  370. PLZDirArray=^TLZDirArray;
  371. TLZDirArray = array[0..MaxChiefLZDirectories] of {$ifdef Win32} string
  372.                                                  {$else Win32}  PString
  373.                                                  {$endif Win32};
  374.  
  375. {////////////////////////////////////////////////////}
  376. Var
  377. buf : PBufType;
  378. jR  : PLZArchiveFiles;
  379. jR2 : PChiefLZArchiveHeader;
  380. {
  381.   This global variable contains a long-string field in Delphi 2; it must
  382.   therefore be initialised if ChiefLZ is to be made into a DLL ...
  383.   (This is a problem with Delphi v2.00 - v2.01 seems to have fixed this)
  384. }
  385. BlankRec: TLZReportRec {$ifdef Win32} = () {$endif Win32};
  386.  
  387. {/////////////////////////////////////////////////////////}
  388. var aRead, aWrite: Longint;
  389. var LZReportProc: TLZReportProc {$ifdef Win32} = nil {$endif Win32};
  390. {
  391.   This global variable ensures that MyReadProc() calls LZReportProc()
  392.   only during compression, and that MyWriteProc() calls LZReportProc()
  393.   only during decompression. This is done by setting Decompressing
  394.   to the appropriate value immediately before calling LZEncode() or
  395.   LZDecode().
  396. }
  397. var Decompressing: Boolean;
  398.  
  399. {/////////////////////////////////////////////////////////}
  400. var InFile, OutFile: file;
  401.  
  402. {/////////////////////////////////////////////////////////}
  403. {$ifdef Win32}
  404. {
  405.   These are Win32-specific functions that cannot be moved into the more
  406.   general ChfUtils due to their dependance on types defined in ChfTypes
  407. }
  408. function GetTempChiefFileName: string;
  409. var
  410.   RetBuf: PChar;
  411. begin
  412.   GetMem(RetBuf, MAX_PATH);
  413.   try
  414.     if (GetTempPath(MAX_PATH, RetBuf) = 0) or
  415.        (GetTempFileName(RetBuf,'CHF',0,RetBuf) = 0) then
  416.       RaiseError(EChiefLZError,SNoTempFileName);
  417.     SetString(Result,RetBuf,StrLen(RetBuf))
  418.   finally
  419.     FreeMem(RetBuf, MAX_PATH)
  420.   end
  421. end;
  422.  
  423. function GetFoundFileName(const Search: TSearchRec): string;
  424. begin
  425.   if Length(Search.Name) >= SizeOf(TLZFileStr) then
  426.     Result := string(Search.FindData.cAlternateFileName)
  427.   else
  428.     Result := Search.Name  // Take long filename (if short enough)
  429. end;                       // else take short filename
  430.  
  431. {$else Win32}
  432.  
  433. function GetTempChiefFileName(const FName: PChar): boolean; assembler;
  434. asm
  435. {
  436.   Create a temporary file- FName must specify a path + '\', with enough
  437.   room afterwards to append 12 characters.
  438. }
  439.   PUSH DS
  440.   LDS DX, FName
  441.   MOV AH, $5A
  442.   MOV CX, faArchive
  443. {$ifdef Windows}
  444.   CALL DOS3Call
  445. {$else Windows}
  446.   INT $21
  447. {$endif Windows}
  448.   POP DS
  449.   JC @Fail
  450. {
  451.   The file handle refers to an OPEN file; close it so we can open it
  452.   the Pascal way ...
  453. }
  454.   MOV BX, AX
  455.   MOV AH, $3E
  456. {$ifdef Windows}
  457.   CALL DOS3Call
  458. {$else Windows}
  459.   INT $21
  460. {$endif Windows}
  461. {
  462.   Return True if successful, False otherwise ...
  463. }
  464. @Fail:
  465. {$ifdef Delphi}
  466.   DB $0F, $93, $C0  (* setnc al *)
  467. {$else Delphi}
  468.   MOV AL, False
  469.   JC @End
  470.   INC AX
  471. @End:
  472. {$endif Delphi}
  473. end;
  474.  
  475. {$endif Win32}
  476.  
  477. {/////////////////////////////////////////////////////////}
  478. {///// is this an LZ compressed file using this unit? ////}
  479. Function IsMyLZFile(Var InFile:file; Var f:TLZHeader):boolean;
  480. var
  481.   OldPos:  LongInt;
  482.   NumRead: Integer;
  483. begin
  484.   OldPos := FilePos(InFile);
  485.   Seek(InFile,0);
  486.   BlockRead(InFile, f, SizeOf(f), NumRead);
  487.   IsMyLZFile := (NumRead = SizeOf(f))
  488.                   and (Length(f.FName) <> 0)
  489.                   and (f.Signature = ChiefLZSig);
  490.   Seek(InFile,OldPos)
  491. end;
  492.  
  493. {/////////////////////////////////////////////////////////}
  494. {////: normal file copy if not LZ file}
  495. const LZ_UNKNOWN_LENGTH = -1;
  496.  
  497. type TReporting = (doReportOnRead, doReportOnWrite);
  498.  
  499. Function MyFCopy(var InFile, OutFile: file;
  500.                  const CopyLength: LongInt;
  501.                  const doReport:   TReporting): LongInt;
  502. {$ifndef Win32} far; {$endif}
  503. Var
  504. p: PBufType;
  505. {
  506.   Turn the enumerated type doReport into a Boolean:
  507.     doReportOnRead  -> False
  508.     doReportOnWrite -> True
  509.  
  510.   Decompression routines will call MyFCopy() using doReportOnWrite,
  511.   whereas Compression routines will call using doReportOnRead
  512. }
  513. var
  514. ReportingOnWrite: Boolean absolute doReport;
  515.  
  516. {$ifdef Win32}
  517. NumRead:integer;
  518. BRead:  integer;
  519. {$else}
  520. BRead:  word;
  521. NumRead:word;
  522. NumWrit:word;
  523. {$endif}
  524. {$ifndef Delphi}
  525. Result: LongInt;
  526. {$endif}
  527.  
  528. begin
  529.  
  530. {$IFDEF Debug}
  531.    if CopyLength < LZ_UNKNOWN_LENGTH then
  532.    {$ifdef Win32}
  533.      raise EChiefLZDebug.Create('Negative copy-length passed to MyFCopy')
  534.        at AddrOfCaller        
  535.    {$else Win32}
  536.      RunErrorMessageAt('Negative copy-length passed to MyFCopy',
  537.                         AddrOfCaller)
  538.    {$endif Win32};
  539. {$ENDIF}
  540.    Result := 0;
  541.    New(p);
  542.  {$ifdef Win32}
  543.    try {finally}
  544.  {$else Win32}
  545.    if p = nil then
  546.      begin
  547.      {$ifndef Delphi}
  548.        MyFCopy := 0;
  549.      {$endif}
  550.        Exit  { ERROR !!! Failed Memory Allocation! }
  551.      end;
  552.  {$endif Win32}
  553.  
  554.    repeat
  555.      if CopyLength <> LZ_UNKNOWN_LENGTH then
  556.        BRead := Min(CopyLength-Result, SizeOf(p^))
  557.      else
  558.        BRead := SizeOf(p^);
  559.      BlockRead(InFile, p^, BRead, NumRead);
  560.  
  561.      {compressing - return number of bytes read}
  562.      if Assigned(LZReportProc) and not ReportingOnWrite then
  563.        LZReportProc(BlankRec, NumRead);
  564. {
  565.   If CopyLength <> LZ_UNKNOWN_LENGTH, we know how many bytes we EXPECT
  566.   to be able to read from this file. If BRead <> NumRead, then the
  567.   file must be corrupt ...
  568. }
  569.    {$ifdef Win32}
  570.      if (CopyLength <> LZ_UNKNOWN_LENGTH) and (BRead <> NumRead) then
  571.        RaiseIOError(SEndOfFile,100); { Will exit via `finally...end' }
  572.    {$endif}
  573. {
  574.   This is the EOF condition for when we DON'T know how long the copy is ...
  575. }
  576.      if NumRead = 0 then
  577.        break;
  578. {
  579.   Without the NumWrit parameter, BlockWrite will cause an IO-Error if the disc
  580.   doesn't have room for SizeOf(p) bytes. This is good in Win32, as an exception
  581.   will then be raised.
  582. }
  583.      BlockWrite(OutFile,p^,NumRead {$ifndef Win32}, NumWrit {$endif});
  584. {
  585.   If Win32 version gets this far, then all NumRead chars must have
  586.   been written ...
  587. }
  588.      inc(Result, {$ifdef Win32} NumRead {$else} NumWrit {$endif});
  589.  
  590.      {de-compressing - return number of bytes written}
  591.      if Assigned(LZReportProc) and ReportingOnWrite then
  592.        LZReportProc(BlankRec, {$ifdef Win32} NumRead {$else} NumWrit {$endif})
  593.  
  594.    until {$ifndef Win32} (NumWrit<>NumRead) or {$endif}
  595.          ( (CopyLength <> LZ_UNKNOWN_LENGTH) and
  596.            (Result >= CopyLength) );
  597.  {$ifndef Delphi}
  598.    MyFCopy := Result;
  599.  {$endif}
  600.  {$ifdef Win32}
  601.    finally
  602.  {$endif}
  603.      Dispose(p);
  604.  {$ifdef Win32}
  605.    end;
  606.  {$endif}
  607. end;
  608.  
  609. {/////////////////////////////////////////////////////////}
  610. Function MyReadProc(var ReadBuf): TLZSSWord; {$ifndef Win32} far; {$endif}
  611. {to read from files}
  612. {$ifndef Delphi}
  613. var
  614.   Result: TLZSSWord;
  615. {$endif}
  616.  
  617. Begin
  618.   BlockRead(InFile, ReadBuf, LZRWBufSize, Result);
  619.   Inc(aRead, Result);
  620.  
  621.  {compressing - return bytes read}
  622.   if Assigned(LZReportProc) and not Decompressing then
  623.     LZReportProc(BlankRec, Result);
  624.  
  625. {$ifndef Delphi}
  626.   MyReadProc := Result
  627. {$endif}
  628. End; { MyReadProc }
  629.  
  630. {/////////////////////////////////////////////////////////}
  631. Function MyWriteProc(var WriteBuf; Count: TLZSSWord): TLZSSWord;
  632. {$ifndef Win32} far; {$endif Win32}
  633. {$ifndef Delphi}
  634. var
  635.   Result: TLZSSWord;
  636. {$endif}
  637. {to write to files}
  638. Begin
  639.   BlockWrite(OutFile, WriteBuf, Count, Result);
  640.   Inc(aWrite, Result);
  641.  
  642.  {de-compressing - return bytes written}
  643.   if Assigned(LZReportProc) and Decompressing then
  644.     LZReportProc(BlankRec, Result);
  645.  
  646. {$ifndef Delphi}
  647.   MyWriteProc := Result
  648. {$endif}
  649. End; { MyWriteProc }
  650.  
  651. {/////////////////////////////////////////////////////////}
  652. Function GetDirIndex(aDir: TLZPathStr; Const DirList: PLZDirArray;
  653.                                        Const Max: TLZSSWord): LongInt;
  654. {find the index of a directory within an array}
  655. Var
  656.   i: TLZSSWord;
  657. begin
  658. {$ifndef Win32}
  659.   aDir := UpperCase(aDir);
  660. {$endif Win32}
  661.   for i := 0 to Max do
  662.     if {$ifdef Win32} AnsiCompareText(aDir, DirList^[i]) = 0
  663.        {$else Win32}  aDir = DirList^[i]^
  664.        {$endif Win32} then
  665.       begin
  666.         GetDirIndex := i;
  667.         Exit
  668.       end;
  669.   GetDirIndex := -1
  670. end;
  671.  
  672. {/////////////////////////////////////////////////////////}
  673. function CreatePath(Path: TLZPathStr): Integer;
  674. {Iteratively create a directory path}
  675. var
  676.   i:      Integer;
  677.   NewDir: TLZPathStr;
  678. {$ifndef Delphi}
  679. {$ifdef Windows}
  680.   P:      array[0..79] of Char;
  681. {$endif Windows}
  682.   Result: Integer;
  683. {$endif Delphi}
  684. begin
  685. {$ifdef Delphi}
  686.   Path := ExpandFileName(Path);
  687. {$else Delphi}
  688.   {$ifdef Windows}
  689.   FileExpand(P, Str2PChar(Path));
  690.   Path := StrPas(p);
  691.   {$else Windows}
  692.   Path := FExpand(Path);
  693.   {$endif Windows}
  694. {$endif Delphi}
  695.  
  696.   i := 3;
  697.   Result := 0;
  698.  
  699.   repeat
  700.     repeat
  701.       Inc(i)
  702.     until (i > Length(Path)) or (Path[i] = '\');
  703.     NewDir := Copy(Path,1,i-1);
  704.     if not DirectoryExists(NewDir) then
  705.       begin
  706.         MkDir(NewDir);         { Win32 throws an exception and exits... }
  707.         {$ifndef Win32}        { We shall catch and handle this     }
  708.         If IOResult <> 0 then  { exception in the calling function. }
  709.           begin
  710.             CreatePath := -1;
  711.             Exit
  712.           end;
  713.        {$endif Win32}
  714.         Inc(Result)
  715.       end
  716.   until i > Length(Path);
  717. {$ifndef Delphi}
  718.   CreatePath := Result;
  719. {$endif}
  720. end;
  721.  
  722. {/////////////////////////////////////////////////////////}
  723. function GetFullLZName(const     X: TChiefLZArchiveHeader;
  724.                              Index: Integer): string;
  725. {$ifdef aDLL} {$ifdef Win32} stdcall
  726.               {$else Win32}  export
  727.               {$endif Win32}; {$endif aDLL}
  728. {$ifndef Delphi}
  729. var
  730.   Result: string;
  731. {$endif}
  732. begin
  733.   Result := '';
  734.   repeat
  735.     with X.Files[Index] do
  736.       begin
  737.         Result := Names + '\' + Result;
  738.         if not IsDir then
  739.           Index := DirID
  740.         else
  741.           Index := ParentDir
  742.       end
  743.   until Index = 0;
  744. {$ifdef Win32}
  745.   SetLength(Result, Pred(Length(Result)));
  746. {$else Win32}
  747.   Dec(Result[0]);
  748. {$endif Win32}
  749. {$ifndef Delphi}
  750.   GetFullLZName := Result;
  751. {$endif Delphi}
  752. end;
  753.  
  754. Function GetFileVersion({$ifdef Win32} Const
  755.                         {$endif} fName: String): TLZVerStr;
  756. {$ifndef DPMI}
  757. {$ifdef TPW}
  758. Var
  759. Result: TLZVerStr;
  760. {$endif TPW}
  761. {$endif DPMI}
  762. Begin
  763.   {$ifdef DPMI}
  764.     GetFileVersion := '0'
  765.   {$else DPMI}
  766.   {$ifdef Windows}
  767.   {$ifdef Win32}
  768.     Result := FileVersionInfo(fName, 'FileVersion');
  769.   {$else Win32}
  770.     Result := FileVersionInfo(Str2PChar(fName), 'FileVersion');
  771.   {$endif Win32}
  772.     if Length(Result) = 0 then
  773.       GetFileVersion := '0'
  774.   {$ifndef Delphi}
  775.     else
  776.       GetFileVersion := Result
  777.   {$endif Delphi}
  778.   {$else Windows}
  779.     GetFileVersion := '0'
  780.   {$endif Windows}
  781.   {$endif DPMI}
  782. End;
  783.  
  784. {/////////////////////////////////////////////////////////}
  785. function GetLZMarkedName(const FName: string): string;
  786. var
  787.   i:   Integer;
  788.   Ext: TLZExtStr;
  789. begin
  790.   Ext := ExtractFileExt(FName);
  791.   i := Length(Ext);
  792.   if i < 2 then             { Ext is either '' or '.' }
  793.     Ext := '.' + MyLZMarker
  794.   else
  795.     Ext[i] := MyLZMarker;
  796.   GetLZMarkedName := ChangeFileExt(FName, Ext)
  797. end;
  798.  
  799. {/////////////////////////////////////////////////////////}
  800. {/////////////////////////////////////////////////////////}
  801. {
  802.   These are the LZ functions exported from the unit
  803. }
  804. {/////////////////////////////////////////////////////////}
  805. {/////////////////////////////////////////////////////////}
  806. Function IsChiefLZArchive(const fName: {$ifdef Win32} string
  807.                                        {$else}        PChar
  808.                                        {$endif} ):boolean;
  809. {$ifdef aDLL} {$ifdef Win32} stdcall
  810.               {$else Win32}  export
  811.               {$endif Win32};
  812. {$endif aDLL}
  813. Var
  814. f:file;
  815. NumRead: TLZSSWord;
  816. {$ifndef Win32}
  817. OldFMode: byte;
  818. {$endif}
  819.  
  820. Hed : TLZArchiveHeader;
  821.  
  822. Begin
  823.      IsChiefLZArchive := False;
  824.  
  825.      if {$ifdef Win32} Length(fName)
  826.         {$else}        StrLen(fName)
  827.         {$endif} = 0 then
  828.        Exit;
  829.  
  830.   {$ifdef Win32}
  831.  
  832.     AssignFile(f, fName);
  833.     FileMode := fmOpenRead; { Win32 only allows 0 <= FileMode <= 2 }
  834.   {$I-}                     { However, share access is FILE_SHARE_READ }
  835.     Reset(f, 1);
  836.   {$I+}
  837.     if IOResult = 0 then
  838.       begin
  839.         BlockRead(f, Hed, SizeOf(Hed), NumRead); // No IO-Error; uses NumRead
  840.         CloseFile(f);
  841.         IsChiefLZArchive := (NumRead = SizeOf(Hed)) and
  842.                             (Hed.Signature = MyLZSignature) and
  843.                             (Hed.Count <> 0)
  844.                  // If haven't read SizeOf(Hed) bytes, CAN'T be LZ Archive
  845.       end
  846.  
  847.    {$else}
  848.  
  849.     Assign(f, StrPas(fName));
  850.     OldFMode := FileMode;
  851. {
  852.   Open file: we need Read-access, don't need Write-access and *INSIST*
  853.   that no one else can write to it (i.e. corrupt it) until we're done.
  854. }
  855.     FileMode := (fmOpenRead or fmShareDenyWrite);
  856.     Reset(f,1);
  857.     FileMode := OldFMode;
  858.     if IOResult = 0 then
  859.       begin
  860.         BlockRead(f, Hed, SizeOf(Hed), NumRead);
  861.         Close(f);
  862.         IsChiefLZArchive := (NumRead = SizeOf(Hed)) and
  863.                             (Hed.Signature = MyLZSignature) and
  864.                             (Hed.Count <> 0)
  865.       end
  866.    {$endif}
  867. end;
  868.  
  869. {/////////////////////////////////////////////////////////}
  870. {$ifdef Win32}
  871. Function GetChiefLZFileName(const fName: string): string;
  872. {$ifdef aDLL} stdcall; {$endif aDLL}
  873. var
  874. f: file;
  875. h: TLZHeader;
  876. begin
  877.   AssignFile(f, fName);
  878.   FileMode := fmOpenRead; { Win32 only allows 0 <= FileMode <= 2 }
  879.   Reset(f,1);             { However, share access is FILE_SHARE_READ }
  880.   try
  881.     if IsMyLZFile(f,h) then
  882.       SetString(Result, PChar(@h.fName[1]), Length(h.fName))
  883.     else
  884.       Result := fName
  885.   finally
  886.     CloseFile(f)
  887.   end
  888. end;
  889. {$else}
  890. Function GetChiefLZFileName(fName, Dest:PChar):boolean;
  891. {$ifdef aDLL} export; {$endif aDLL}
  892. Var
  893. h:TLZHeader;
  894. f:file;
  895. {$ifndef Delphi}
  896. Result:boolean;
  897. {$endif}
  898. OldFMode:byte;
  899. Begin
  900.     GetChiefLZFileName := false;
  901.     StrCopy(Dest, fName); {return filename}
  902.     Assign(f, StrPas(fName));
  903.     OldFMode := FileMode;
  904. {
  905.   Open file: we need Read-access, don't need Write access, and *INSIST*
  906.   that no one else can write to it (i.e. corrupt it) until we're done.
  907. }
  908.     FileMode := (fmOpenRead or fmShareDenyWrite);
  909.     Reset(f,1);
  910.     FileMode := OldFMode;
  911.     if IOResult=0 then
  912.       begin
  913.         Result := IsMyLZfile(f,h);
  914.         Close(f);  { Reset() OK, so Close() must succeed }
  915.       {$ifndef Delphi}
  916.         GetChiefLZFileName := Result;
  917.       {$endif Delphi}
  918.         if Result then
  919.           StrPCopy(Dest, h.fName);
  920.       end
  921. end;
  922. {$endif}
  923. {/////////////////////////////////////////////////////////}
  924. {/////////////////////////////////////////////////////////}
  925. Function GetChiefLZFileSize(fName: {$ifdef Win32} string
  926.                                    {$else}        PChar
  927.                                    {$endif}):LongInt;
  928. {$ifdef aDLL} {$ifdef Win32} stdcall
  929.               {$else Win32}  export
  930.               {$endif Win32};
  931. {$endif aDLL}
  932. Var
  933. h:TLZHeader;
  934. f:file;
  935. {$ifndef Win32}
  936. OldFMode:byte;
  937. {$endif}
  938.  
  939. Begin
  940.   {$ifdef Win32}
  941.     AssignFile(f,fName);
  942.     FileMode := fmOpenRead; { Win32 only allows 0 <= FileMode <= 2 }
  943.     Reset(f,1);             { However, share access is FILE_SHARE_READ }
  944.     try
  945.       if IsMyLZFile(f,h) then
  946.         Result := h.uSize
  947.       else
  948.         Result := FileSize(f)
  949.     finally
  950.       CloseFile(f)
  951.     end;
  952.   {$else}
  953.     GetChiefLZFileSize := -1{error};
  954.     Assign(f, StrPas(fName));
  955.     OldFMode := FileMode;
  956. {
  957.   Open file: we need Read-access, don't need Write-access and *INSIST*
  958.   that no one else can write to it (i.e. corrupt it) until we're done.
  959. }
  960.     FileMode := (fmOpenRead or fmShareDenyWrite);
  961.     Reset(f,1);
  962.     FileMode := OldFMode;
  963.     if IOResult=0 then
  964.       begin
  965.  
  966.         if IsMyLZFile(f,h) then
  967.           GetChiefLZFileSize := h.uSize      {uncompressed size}
  968.         else
  969.           GetChiefLZFileSize := FileSize(f); {actual size}
  970.         Close(f);         { Reset() OK, so Close() cannot fail }
  971.  
  972.       end;
  973.   {$endif}
  974. end;
  975. {/////////////////////////////////////////////////////////}
  976.  
  977. function GetChiefLZArchiveInfo(const ArchName: {$ifdef Win32} string
  978.                                                {$else Win32}  PChar
  979.                                                {$endif Win32};
  980.                                var   Header: TChiefLZArchiveHeader): boolean;
  981. {$ifdef aDLL} {$ifdef Win32} stdcall
  982.               {$else Win32}  export
  983.               {$endif Win32};
  984. {$endif aDLL}
  985. var
  986.   f       : file;
  987.   Hed     : TLZArchiveHeader;
  988. {$ifndef Win32}
  989.   OldFMode: byte;
  990. {$endif Win32}
  991. begin
  992. {$ifdef Win32}
  993.  
  994.   Result := IsChiefLZArchive(ArchName);
  995.   if Result then
  996.     begin
  997.       AssignFile(f,ArchName);
  998.       FileMode := fmOpenRead; { Win32 only allows 0 <= FileMode <= 2 }
  999.       Reset(f,1);             { However, share access is FILE_SHARE_READ }
  1000.       try
  1001.         BlockRead(f, Hed, SizeOf(Hed)); {read archive header}
  1002.         Header.Count := Hed.Count;
  1003.         BlockRead(f, Header.Files[1], SizeOf(TLZFileRec)*Hed.Count)
  1004.       finally
  1005.         CloseFile(f)
  1006.       end
  1007.     end
  1008.  
  1009. {$else Win32}
  1010.  
  1011.     GetChiefLZArchiveInfo := False;
  1012.     If IsChiefLZArchive(ArchName) then
  1013.       begin
  1014.         Assign(f, StrPas(ArchName));
  1015.         OldFMode := FileMode;
  1016. {
  1017.   Open file: we need Read-access, don't need Write-access and *INSIST*
  1018.   that no one can write to it (i.e. corrupt it) until we're done ...
  1019. }
  1020.         FileMode := (fmOpenRead or fmShareDenyWrite);
  1021.         Reset(f, 1);
  1022.         FileMode := OldFMode;
  1023.         if IOResult=0 then
  1024.           begin
  1025.             BlockRead(f, Hed, SizeOf(Hed)); {read archive header}
  1026.             If IOResult=0 then
  1027.             begin
  1028.               Header.Count := Hed.Count;
  1029.               BlockRead(f, Header.Files[1], SizeOf(TLZFileRec)*Hed.Count);
  1030.               if IOResult=0 then
  1031.                 GetChiefLZArchiveInfo := True;
  1032.               Close(f) { If successful open, Close() MUST succeed here }
  1033.             end
  1034.           end
  1035.       end
  1036.  
  1037. {$endif Win32}
  1038. End;
  1039.  
  1040. {/////////////////////////////////////////////////////////}
  1041. Function GetChiefLZArchiveSize(const ArchName: {$ifdef Win32} string
  1042.                                                {$else Win32}  PChar
  1043.                                                {$endif Win32}): LongInt;
  1044. {$ifdef aDLL} {$ifdef Win32} stdcall
  1045.               {$else Win32}  export
  1046.               {$endif Win32};
  1047. {$endif aDLL}
  1048. {get uncompressed size of archive}
  1049. Var
  1050. X: PChiefLZArchiveHeader;
  1051. i: Longint;
  1052. {$ifndef Delphi}
  1053. Result: LongInt;
  1054. {$endif Delphi}
  1055. Begin
  1056.   New(X);
  1057. {$ifdef Win32}
  1058.   try { finally }
  1059. {$endif Win32}
  1060.   if not GetChiefLZArchiveInfo(ArchName, X^) then
  1061.     GetChiefLZArchiveSize := FSize({$ifdef Win32} ArchName
  1062.                                    {$else Win32}  StrPas(ArchName)
  1063.                                    {$endif Win32})
  1064.   else
  1065.     begin
  1066.       Result := 0;
  1067.       with X^ do
  1068.         for i := 1 to Count do
  1069.           Inc(Result, Files[i].uSizes);
  1070.     {$ifndef Delphi}
  1071.       GetChiefLZArchiveSize := Result
  1072.     {$endif Delphi}
  1073.     end;
  1074. {$ifdef Win32}
  1075.   finally
  1076. {$endif Win32}
  1077.   Dispose(X)
  1078. {$ifdef Win32}
  1079.   end
  1080. {$endif Win32}
  1081. End;
  1082.  
  1083. {/////////////////////////////////////////////////////////}
  1084. Function LZCompress(const {$ifdef Win32} Source, Dest:   string
  1085.                           {$else}        aSource, aDest: pChar
  1086.                           {$endif};
  1087.                     LZQuestion  :TLZQuestionFunc;
  1088.                     aProc:TLZReportProc):LongInt;
  1089. {$ifdef aDLL} {$ifdef Win32} stdcall
  1090.               {$else Win32}  export
  1091.               {$endif Win32};
  1092. {$endif aDLL}
  1093. Var
  1094. {$ifndef Win32}
  1095. OldFMode : byte;
  1096. Source,
  1097. Dest     : String;
  1098. {$endif}
  1099. f     : TLZHeader;
  1100. RepRec: TLZReportRec;
  1101. hT    : LongInt;
  1102.  
  1103. Begin
  1104.  
  1105. {$ifDef aDLL}
  1106.   If IsLZInitialized then
  1107.   {$ifdef Win32}
  1108.     RaiseError(EChiefLZDLL,SBusyChief);
  1109.   {$else}
  1110.     begin
  1111.       LZCompress := -20;  {already busy}
  1112.       Exit
  1113.     end;
  1114.   {$endif}
  1115. {$endif aDLL}
  1116.  
  1117.   aRead := 0;
  1118.   aWrite:= 0;
  1119.  
  1120.   if not LZInit then
  1121.   {$ifdef Win32}
  1122.     RaiseError(EChiefLZError,SInitFailed);
  1123.   {$else}
  1124.     begin
  1125.       LZCompress := -10;  {unable to init}
  1126.       Exit
  1127.     end;
  1128.   {$endif}
  1129.  
  1130. {$ifdef Win32}
  1131.   try { finally }
  1132. {$endif}
  1133.  
  1134.   {$ifdef Win32}
  1135.   if (Length(Source)=0) or (Length(Dest)=0) then
  1136.     RaiseError(EChiefLZCompress,SInvalidParams);
  1137.   if AnsiCompareText(Source, Dest) = 0 then
  1138.     RaiseErrorStr(EChiefLZCompress,SSameFileName,Source);
  1139.   {$else}
  1140.   Source := StrPas(aSource);
  1141.   Dest   := StrPas(aDest);
  1142.   If (Length(Source)=0) or (Length(Dest)=0) or
  1143.                                   (Uppercase(Source)=Uppercase(Dest))
  1144.   then
  1145.   begin
  1146.     LZCompress := -11;  {same source and target}
  1147.     LZDone;
  1148.     Exit
  1149.   end
  1150.   {$endif};
  1151.  
  1152.   hT := sFTime(Source);
  1153.  
  1154. {||| does target file exist already? ||||}
  1155.   If FileExists(Dest) then
  1156.     begin
  1157.       With RepRec do
  1158.         begin   {details of Source}
  1159.           Names  := Source;
  1160.           Sizes  := fSize(Source);
  1161.           uSizes := Sizes;
  1162.           Times  := hT;
  1163.           FileVersion := GetFileVersion(Source);
  1164.         end;
  1165.  
  1166.       if Assigned(LZQuestion) then
  1167.         if LZQuestion(RepRec, Dest) <> LZYes then
  1168.           begin
  1169.             LZCompress := -100; {target exists - don't overwrite}
  1170.           {$ifndef Win32}
  1171.             LZDone;
  1172.           {$endif}
  1173.             Exit
  1174.           end
  1175.     end
  1176.   else
  1177.     With RepRec do
  1178.       begin
  1179.         Names  := Source;
  1180.         Times  := ht;
  1181.         uSizes := FSize(Source);
  1182.         Sizes  := -1;
  1183.         FileVersion := GetFileVersion(Source);
  1184.       end;
  1185.   BlankRec := RepRec;
  1186.  
  1187. {$ifdef Win32}
  1188.   AssignFile(InFile, Source);
  1189.   FileMode := fmOpenRead; { Win32 only allows 0 <= FileMode <= 2 }
  1190.   Reset(InFile,1);        { However, share access is FILE_SHARE_READ }
  1191.   try { finally }
  1192.     AssignFile(OutFile, Dest);
  1193.     Rewrite(OutFile,1);
  1194.     try { finally }
  1195.  
  1196.       If Assigned(aProc) then aProc(RepRec, -1);
  1197.       LZReportProc := aProc;
  1198.  
  1199.       if IsMyLZFile(InFile, f) then
  1200.         LZCompress := MyFCopy(InFile,OutFile,
  1201.                                LZ_UNKNOWN_LENGTH,doReportOnRead)
  1202.       else                               {already compressed: just copy}
  1203.         begin
  1204.           FillChar(f, SizeOf(f), 0);
  1205.           with f do
  1206.             begin
  1207.               fName := ExtractFileName(Source);
  1208.               fTime := hT;
  1209.               Signature := ChiefLZSig;
  1210.               uSize := RepRec.USizes{FileSize(InFile)};
  1211.               Version := RepRec.FileVersion;
  1212.             end;
  1213.           BlockWrite(OutFile, f, SizeOf(f)); {write header}
  1214.  
  1215.           InBufPtr := LZRWBufSize;
  1216.           InBufSize := LZRWBufSize;
  1217.           OutBufPtr := 0;
  1218.           Height := 0;
  1219.           MatchPos := 0;
  1220.           MatchLen := 0;
  1221.           LastLen := 0;
  1222.  
  1223.           FillChar(BinaryTree^, SizeOf(TBinaryTree), 0);
  1224.           FillChar(CodeBuf, SizeOf(CodeBuf), 0);
  1225.           Decompressing := False;
  1226.           LZEncode;
  1227.  
  1228.           {go back and rewrite header}
  1229.           f.cSize := aWrite;
  1230.           Seek(OutFile,0);
  1231.           BlockWrite(OutFile, f, SizeOf(f)); {write header}
  1232.  
  1233.           LZCompress := aWrite+SizeOf(TLZHeader)
  1234.         end
  1235.  
  1236.     finally
  1237.       FileSetDate(TFileRec(OutFile).Handle, f.fTime);
  1238.       CloseFile(OutFile);
  1239.       if Assigned(aProc) then
  1240.         begin
  1241.           RepRec.Names := '';
  1242.           aProc(RepRec, -2)
  1243.         end
  1244.     end
  1245.   finally
  1246.     CloseFile(InFile)
  1247.   end
  1248.   finally
  1249.     LZDone
  1250.   end
  1251.  
  1252. {$else}
  1253.  
  1254.   Assign(InFile, Source);
  1255.   OldFMode := FileMode;
  1256. {
  1257.   Open file: we need Read-access, don't need Write-access and *INSIST*
  1258.   that no one else can write to it (i.e. corrupt it) 'til we're done ...
  1259. }
  1260.   FileMode := (fmOpenRead or fmShareDenyWrite);
  1261.   Reset(InFile, 1);
  1262.   FileMode := OldFMode;
  1263.   if IOResult<>0 then
  1264.     LZCompress := -2
  1265.   else begin
  1266.  
  1267.   Assign(OutFile, Dest);
  1268.   Rewrite(OutFile, 1);
  1269.   if IOResult<>0 then
  1270.     LZCompress := -3
  1271.   else begin
  1272.  
  1273.   If Assigned(aProc) then aProc(RepRec, -1);
  1274.   LZReportProc := aProc;
  1275.  
  1276.   If IsMyLZFile(InFile, f) then
  1277.     LZCompress := MyFCopy(InFile,OutFile,LZ_UNKNOWN_LENGTH,doReportOnRead)
  1278.   else                                   {already compressed: just copy}
  1279.     begin
  1280.      FillChar(f, SizeOf(f), 0);
  1281.      With f do
  1282.        begin
  1283.          fName := ExtractFileName(Source);
  1284.          fTime := hT;
  1285.          uSize := FileSize(InFile);
  1286.          Signature  := ChiefLZSig;
  1287.          Version := RepRec.FileVersion;
  1288.        end;
  1289.      BlockWrite(OutFile, f, SizeOf(f)); {write header}
  1290.  
  1291.      if IOResult <> 0 then
  1292.        LZCompress := -4
  1293.      else
  1294.        begin
  1295.          InBufPtr := LZRWBufSize;
  1296.          InBufSize := LZRWBufSize;
  1297.          OutBufPtr := 0;
  1298.          Height := 0;
  1299.          MatchPos := 0;
  1300.          MatchLen := 0;
  1301.          LastLen := 0;
  1302.  
  1303.          FillChar(BinaryTree^, SizeOf(TBinaryTree), 0);
  1304.          FillChar(CodeBuf, SizeOf(CodeBuf), 0);
  1305.          Decompressing := False;
  1306.          LZEncode;
  1307.  
  1308.          {go back and rewrite header}
  1309.          f.cSize := aWrite;
  1310.          Seek(Outfile, 0);if IOResult<>0 then;
  1311.          BlockWrite(OutFile, f, SizeOf(f)); {write header}
  1312.  
  1313.          LZCompress := aWrite+SizeOf(TLZHeader)
  1314.        end
  1315.     end;
  1316.  
  1317.   if Assigned(aProc) then
  1318.     begin
  1319.       RepRec.Names := '';
  1320.       aProc(RepRec, -2)
  1321.     end;
  1322.  
  1323.   { set date/time stamp }
  1324. {$ifdef Delphi}
  1325.   FileSetDate(TFileRec(OutFile).Handle, f.fTime);
  1326. {$else}
  1327.   SetFTime(OutFile, f.fTime);
  1328. {$endif}
  1329.  
  1330.   Close(OutFile);if IOResult<>0 then;
  1331.   end; { IOResult = 0 }
  1332.  
  1333.   Close(InFile);if IOResult<>0 then;
  1334.   end; { IOResult = 0 }
  1335.  
  1336.   LZDone
  1337. {$endif}
  1338. End; { LZCompress }
  1339. {/////////////////////////////////////////////////////////}
  1340. {/////////////////////////////////////////////////////////}
  1341. {/////////////////////////////////////////////////////////}
  1342. Function LZDecompress({$ifdef Win32} Source, Dest:  string
  1343.                       {$else} const aSource, aDest: PChar
  1344.                       {$endif};
  1345.                       LZQuestion: TLZQuestionFunc;
  1346.                       aProc:      TLZReportProc):LongInt;
  1347. {$ifdef aDLL} {$ifdef Win32} stdcall
  1348.               {$else Win32}  export 
  1349.               {$endif Win32};
  1350. {$endif aDLL}
  1351.  
  1352. Var
  1353. f     : TLZHeader;
  1354. hT    : LongInt;
  1355. RepRec: TLZReportRec;
  1356. IsComp: Boolean;
  1357.  
  1358. {$ifndef Win32}
  1359. Source,
  1360. UpSource,
  1361. Dest    : TLZPathStr;
  1362. OldFMode: Byte;
  1363. LZReply : TLZReply;
  1364. {$endif}
  1365. p    : {$ifdef Win32} string;
  1366.        {$else}        array[0..79] of Char;
  1367.        {$endif}
  1368.  
  1369. Begin
  1370.  
  1371. {$ifDef aDLL}
  1372.   If IsLZInitialized then
  1373.   {$ifdef Win32}
  1374.     RaiseError(EChiefLZDLL,SBusyChief);
  1375.   {$else}
  1376.     begin
  1377.       LZDecompress := -20;  {already busy}
  1378.       Exit
  1379.     end
  1380.   {$endif};
  1381. {$endif aDLL}
  1382.  
  1383.   aRead := 0;
  1384.   aWrite:=0;
  1385.  
  1386.   if not LZInit then
  1387.   {$ifdef Win32}
  1388.     RaiseError(EChiefLZError,SInitFailed);
  1389.   {$else}
  1390.     begin
  1391.       LZDecompress := -10;  {unable to init}
  1392.       Exit
  1393.     end;
  1394.   {$endif}
  1395.  
  1396. {$ifdef Win32}
  1397.   try { finally }
  1398.  
  1399.   if (Length(Source)=0) or (Length(Dest)=0) then
  1400.     RaiseError(EChiefLZCompress,SInvalidParams);
  1401.  
  1402.   Source := ExpandFileName(Source);
  1403.   Dest   := ExpandFileName(Dest);
  1404. {
  1405.   Do case-insensitive comparison of full pathnames ...
  1406. }
  1407.   if AnsiCompareText(Source, Dest) = 0 then
  1408.     RaiseErrorStr(EChiefLZCompress,SSameFileName,Source);
  1409.  
  1410. {$else}
  1411.  
  1412.   Source   := StrPas(aSource);
  1413.   UpSource := Uppercase(Source);
  1414.   Dest     := StrPas(aDest);
  1415.   If (Length(Source)=0) or (Length(Dest)=0)
  1416.         or (UpSource=Uppercase(Dest))
  1417.   then
  1418.     LZDecompress := -11
  1419.   else begin
  1420.  
  1421. {$endif}
  1422.  
  1423.   {see if source file exists}
  1424.   {$ifdef Win32}
  1425.     p := '';
  1426.   {$else}
  1427.     p[0] := #0;
  1428.   {$endif}
  1429.  
  1430.     If Not FileExists(Source) then {look for name ending with MyLZMarker}
  1431.     begin
  1432.        Source := GetLZMarkedName(Source);
  1433. {
  1434.   Win32 will raise the correct exception automatically when
  1435.   GetChiefLZFileName() attempts to open Source ...
  1436. }
  1437.      {$ifdef Win32}
  1438.  
  1439.        p := GetChiefLZFileName(Source);
  1440.        if AnsiCompareText(ExtractFileName(p),
  1441.                           ExtractFileName(Source)) <> 0 then
  1442.          RaiseErrorStr(EChiefLZCompress,SWrongCompressedFile,p);
  1443.  
  1444.      {$else}
  1445.  
  1446.        If Not FileExists(Source) then {source file not found}
  1447.          begin
  1448.            LZDecompress := -12;
  1449.            LZDone;
  1450.            Exit
  1451.          end;
  1452.  
  1453.        GetChiefLZFileName(Str2PChar(Source), p); {read header}
  1454.        If (ExtractFileName(Uppercase(StrPas(p)))
  1455.             <> ExtractFileName(UpSource)) {wrong uncompressed file}
  1456.        then begin
  1457.           LZDecompress := -3; {wrong file}
  1458.           LZDone;
  1459.           Exit
  1460.         end;
  1461.      {$endif}
  1462.     end;
  1463.  
  1464.     {not FileExists}
  1465.   {||||||||}
  1466.   hT := sFTime(Source);
  1467.  
  1468.   {$ifdef Win32}
  1469.  
  1470.   AssignFile(InFile, Source);
  1471.   FileMode := fmOpenRead; { Win32 only allows 0 <= FileMode <= 2 }
  1472.   Reset(InFile, 1);       { However, share access is FILE_SHARE_READ }
  1473.   try { finally }
  1474.  
  1475.   {$else Win32}
  1476.  
  1477.   Assign(InFile, Source);
  1478.   OldFMode := FileMode;
  1479.   FileMode := (fmOpenRead or fmShareDenyWrite); {using these constants causes problems!}
  1480.   Reset(InFile, 1);                         { Only if file is already open for       }
  1481.   FileMode := OldFMode;                     { *writing* to by another process.       }
  1482.                                             { If a write happens during decomression }
  1483.   if IOResult <> 0 then                     { then the decompressed file is worthless}
  1484.     LZDecompress := -12 {can't open source}
  1485.   else begin
  1486.  
  1487.   {$endif Win32}
  1488.  
  1489.   IsComp := IsMyLZFile(InFile, f);
  1490.  
  1491. {||| does target file exist already? ||||}
  1492.   If FileExists(Dest) then begin
  1493.     with RepRec do
  1494.       If IsComp then
  1495.         begin {send details of Source(compressed) file}
  1496.           Names  := {AddBackSlash(ExtractFilePath(Source))+}f.fName{Source};
  1497.           Sizes  := f.cSize;
  1498.           uSizes := f.uSize;
  1499.           Times  := f.fTime;
  1500.           FileVersion := f.Version;
  1501.         end
  1502.       else begin
  1503.         Names  := Source;
  1504.         Sizes  := FileSize(InFile);
  1505.         uSizes := Sizes;
  1506.         Times  := hT;
  1507.         FileVersion := GetFileVersion(Source);
  1508.       end;
  1509.  
  1510.     if Assigned(LZQuestion) then    { and send name of existing target file}
  1511.     {$ifdef Win32}
  1512.       case LZQuestion(RepRec, Dest) of
  1513.         LZNo:   begin
  1514.                   LZDecompress := -100; {target exists - don't overwrite}
  1515.                   Exit
  1516.                 end;
  1517.         LZQuit: Abort { Raises a silent-exception... Fast-track exit   }
  1518.       end             { out of entire application unless caught... :-) }
  1519.     {$else Win32}
  1520.       begin
  1521.         LZReply := LZQuestion(RepRec, Dest);
  1522.         if LZReply <> LZYes then
  1523.           begin
  1524.             if LZReply = LZNo then
  1525.               LZDecompress := -100   { Exit nicely ... }
  1526.             else
  1527.               LZDecompress := -150;  { ABORT!!!!!!!    }
  1528.             Close(InFile); { Reset() successful; Close() cannot fail }
  1529.             LZDone;
  1530.             Exit
  1531.           end
  1532.       end
  1533.     {$endif Win32}
  1534.  
  1535.   End;
  1536.  
  1537.   {report on target file}
  1538.   With RepRec do begin
  1539.      Names := Dest;
  1540.      If IsComp then begin
  1541.         Sizes  := f.cSize;
  1542.         uSizes := f.uSize;
  1543.         Times  := f.fTime;
  1544.         FileVersion := f.Version;
  1545.      end else begin
  1546.        Sizes  := fSize(Source);
  1547.        uSizes := Sizes;
  1548.        Times  := hT;
  1549.        FileVersion := '0';
  1550.      end;
  1551.   end;
  1552.  
  1553.   BlankRec := RepRec;
  1554.  
  1555. {$ifdef Win32}
  1556.     AssignFile(OutFile, Dest);
  1557.     Rewrite(OutFile, 1);
  1558.     try { finally }
  1559.  
  1560.       {//////////}
  1561.       if Assigned(aProc) then aProc(RepRec, -1);
  1562.       LZReportProc := aProc;
  1563.       {//////////}
  1564.       if not IsComp then
  1565.         begin {normal copy}
  1566.           f.fTime := hT{lFTime(InFile)};
  1567.           LZDecompress := MyFCopy(InFile,OutFile,
  1568.                                   LZ_UNKNOWN_LENGTH,doReportOnWrite)
  1569.         end
  1570.       else
  1571.         begin
  1572.           InBufPtr  := LZRWBufSize;
  1573.           InBufSize := LZRWBufSize;
  1574.           OutBufPtr := 0;
  1575.           FillChar(BinaryTree^.TextBuf, SizeOf(TLZTextBuf), 0);
  1576.           Seek(InFile, SizeOf(TLZHeader));
  1577.           Decompressing := True;
  1578.           LZDecode;
  1579.           LZDecompress := aWrite
  1580.         end
  1581.  
  1582.     finally
  1583.       { set date/time stamp }
  1584.       FileSetDate(TFileRec(OutFile).Handle, f.fTime);
  1585.       CloseFile(OutFile);
  1586.       if Assigned(aProc) then
  1587.         begin
  1588.           RepRec.Names := '';
  1589.           aProc(RepRec, -2)
  1590.         end
  1591.     end
  1592.  
  1593.   finally
  1594.     CloseFile(InFile)
  1595.   end
  1596.   finally
  1597.     LZDone
  1598.   end;
  1599. {$else}
  1600.   Assign(OutFile, Dest);
  1601.   Rewrite(OutFile, 1);
  1602.   if IOResult <> 0 then
  1603.     LZDecompress := -13  {can't open target}
  1604.   else begin
  1605.  
  1606.   {//////////}
  1607.   if Assigned(aProc) then aProc(RepRec, -1);
  1608.   LZReportProc := aProc;
  1609.   {//////////}
  1610.   if not IsComp{IsMyLZFile(InFile, f)} then
  1611.     begin {normal copy}
  1612.       f.fTime := hT{lFTime(InFile)};
  1613.       LZDecompress := MyFCopy(InFile,OutFile,
  1614.                               LZ_UNKNOWN_LENGTH,doReportOnWrite)
  1615.     end
  1616.   {//////////}
  1617.   else
  1618.     begin
  1619.       InBufPtr  := LZRWBufSize;
  1620.       InBufSize := LZRWBufSize;
  1621.       OutBufPtr := 0;
  1622.       FillChar(BinaryTree^.TextBuf, SizeOf(TLZTextBuf), 0);
  1623.       Seek(InFile, SizeOf(TLZHeader));
  1624.       Decompressing := True;
  1625.       LZDecode;
  1626.       LZDecompress := aWrite
  1627.     end;
  1628.  
  1629. { set date/time stamp }
  1630. {$ifdef Delphi}
  1631.   FileSetDate(TFileRec(OutFile).Handle, f.fTime);
  1632. {$else}
  1633.   SetFTime(OutFile, f.fTime);
  1634. {$endif}
  1635.   Close(OutFile);if IOResult<>0 then;
  1636.   if Assigned(aProc) then
  1637.     begin
  1638.       RepRec.Names := '';
  1639.       aProc(RepRec, -2)
  1640.     end
  1641.   end; { IOResult = 0 }
  1642.  
  1643.   Close(InFile); if IOResult<>0 then;
  1644.   end { IOResult = 0 }
  1645.  
  1646.   end;
  1647.   LZDone
  1648. {$endif}
  1649. End; { LZDecompress }
  1650.  
  1651. {/////////////////////////////////////////////////////////}
  1652.  
  1653. Function IsChiefLZFile(const fName: {$ifdef Win32} string
  1654.                                     {$else}        PChar
  1655.                                     {$endif}):boolean;
  1656. {$ifdef aDLL} {$ifdef Win32} stdcall
  1657.               {$else Win32}  export
  1658.               {$endif Win32};
  1659. {$endif aDLL}
  1660.  
  1661. Var
  1662. h:TLZHeader;
  1663. f:file;
  1664. {$ifndef Win32}
  1665. OldFMode: byte;
  1666. {$endif}
  1667. Begin
  1668.   {$ifdef Win32}
  1669.     AssignFile(f, fName);
  1670.     FileMode := fmOpenRead; { Win32 only allows 0 <= FileMode <= 2     }
  1671.     Reset(f,1);             { However, share access is FILE_SHARE_READ }
  1672.     try
  1673.       Result := IsMyLZFile(f,h)
  1674.     finally
  1675.       CloseFile(f)
  1676.     end
  1677.   {$else}
  1678.     IsChiefLZFile := False;
  1679.     Assign(f, StrPas(fName));
  1680.     OldFMode := FileMode;
  1681. {
  1682.   Open file: we need Read-access, don't need Write-access and *INSIST*
  1683.   that no one else can write to it (i.e. corrupt it) 'til we're done ...
  1684. }
  1685.     FileMode := (fmOpenRead or fmShareDenyWrite);
  1686.     Reset(f,1);
  1687.     FileMode := OldFMode;
  1688.     if IOResult=0 then
  1689.       begin
  1690.         IsChiefLZFile := IsMyLZFile(f,h);
  1691.         Close(f) { ReadOnly Reset() succeeded; Close() MUST succeed }
  1692.       end
  1693.   {$endif}
  1694. end;
  1695. {/////////////////////////////////////////////////////////}
  1696. {/////////////////////////////////////////////////////////}
  1697. {/////////////////////////////////////////////////////////}
  1698. {/////////////////////////////////////////////////////////}
  1699. Function ArchiveSquash(Var InFile, OutFile: file;
  1700.                        Const aProc: TLZReportProc):LongInt;
  1701. Begin
  1702.   ArchiveSquash := -1;
  1703.   if IsLZInitialized then
  1704.   begin
  1705.     Seek(InFile, 0);{$ifndef Win32} if IOResult<>0 then; {$endif}
  1706.  
  1707.     LZReportProc := aProc;
  1708.     InBufPtr     := LZRWBufSize;
  1709.     InBufSize    := LZRWBufSize;
  1710.     OutBufPtr    := 0;
  1711.     Height       := 0;
  1712.     MatchPos     := 0;
  1713.     MatchLen     := 0;
  1714.     LastLen      := 0;
  1715.     aWrite       := 0;
  1716.  
  1717.     FillChar(BinaryTree^, SizeOf(TBinaryTree), 0);
  1718.     FillChar(CodeBuf, SizeOf(CodeBuf), 0);
  1719.     Decompressing := False;
  1720.     LZEncode;
  1721.     ArchiveSquash := aWrite
  1722.   end; {IsLZInitialized}
  1723. End; { ArchiveSquash }
  1724.  
  1725. {/////////////////////////////////////////////////////////}
  1726. Function IsFileInDir({$ifdef Delphi} const {$endif} fSpec:String):Boolean;
  1727. Var
  1728. {$ifdef Windows}
  1729.  Dir:TSearchRec;
  1730. {$else}
  1731.  Dir:SearchRec;
  1732. {$endif Windows}
  1733. Begin
  1734.    {$ifdef Delphi}
  1735.      Result := (FindFirst(fSpec, faAnyFile-faDirectory-faVolumeID, Dir)=0);
  1736.      if Result then
  1737.        SysUtils.FindClose(Dir);
  1738.    {$else Delphi}
  1739.  
  1740.    {$ifdef Windows}
  1741.      FindFirst(Str2PChar(fSpec), faAnyFile-faDirectory-faVolumeID, Dir);
  1742.    {$else Windows}
  1743.      FindFirst(fSpec,AnyFile-Directory-VolumeID, Dir);
  1744.    {$endif Windows}
  1745.      IsFileInDir := (DosError = 0)
  1746.  
  1747.     {$endif Delphi}
  1748. End;
  1749.  
  1750. {//////////////////////////////////////////}
  1751. Procedure InitReportRec(Var RepRec:TLZReportRec; Const X:TLZBigFileRec);
  1752. Begin
  1753.    With RepRec, X do
  1754.      begin
  1755.        Names := BigNames;
  1756.        Sizes := BigSizes;
  1757.        uSizes:= uBigSizes;
  1758.        Times := BigTimes;
  1759.        FileVersion := BigFileVersion;
  1760.        IsDir := IsBigDir
  1761.     end
  1762. End;
  1763.  
  1764. {/////////////////////////////////////////////////////////}
  1765. Function LZArchive(const fSpec, ArchName: {$ifdef Win32} string
  1766.                                           {$else}        PChar
  1767.                                           {$endif};
  1768.                    LZRecurseDirs: TLZRecurse;
  1769.                    aProc:         TLZReportProc):LongInt;
  1770. {$ifdef aDLL} {$ifdef Win32} stdcall
  1771.               {$else Win32}  export
  1772.               {$endif Win32};
  1773. {$endif aDLL}
  1774.  
  1775. type
  1776.   PDirTimes = ^TDirTimes;
  1777.   TDirTimes = array[1..MaxChiefLZDirectories] of LongInt;
  1778.  
  1779. Const
  1780. {$ifdef Windows}
  1781.   faFiles = faReadOnly+faSysFile+faHidden+faArchive+0;
  1782.   faDirs  = faSysFile+faHidden+faDirectory+0;
  1783. {$else Windows}
  1784.   faFiles = ReadOnly+SysFile+Hidden+Archive+0;
  1785.   faDirs  = SysFile+Hidden+Directory+0;
  1786. {$endif Windows}
  1787.  
  1788. VAR
  1789. {$ifdef Windows}
  1790.  Dir:  TSearchRec;
  1791. {$else Windows}
  1792.  Dir:  SearchRec;
  1793. {$endif Windows}
  1794.  
  1795. {$ifndef Win32}
  1796. OldFMode   : byte;
  1797. Temp       : TLZPathStr;
  1798. l, LZTot   : LongInt;
  1799. {$endif Win32}
  1800.  
  1801. Path,
  1802. s1, s2     : TLZPathStr;
  1803. fSpecName  : TLZPathStr;
  1804. i          : LongInt;
  1805. t          : Text;
  1806. UseFile    : boolean;
  1807. Hed        : TLZArchiveHeader;
  1808. FoundName  : TLZPathStr;
  1809. MemRec,
  1810. DirCount,
  1811. DirCountEx : TLZSSWord;
  1812. DirArray   : PLZDirArray;
  1813. DirTimes   : PDirTimes;
  1814. PIndex     : LongInt;
  1815. NewPIndex  : LongInt;
  1816. RepRec     : TLZReportRec;
  1817.  
  1818. begin
  1819. {$ifdef aDLL}
  1820.   if IsLZInitialized then
  1821.   {$ifdef Win32}
  1822.     RaiseError(EChiefLZDLL,SBusyChief);
  1823.   {$else}
  1824.     begin
  1825.       LZArchive := -20; {busy}
  1826.       Exit
  1827.     end
  1828.   {$endif};
  1829.  {$endif aDLL}
  1830.  
  1831.   if not LZInit then
  1832.   {$ifdef Win32}
  1833.     RaiseError(EChiefLZError,SInitFailed);
  1834.   {$else}
  1835.     begin
  1836.       LZArchive := -10; {init error}
  1837.       Exit
  1838.     end;
  1839.   {$endif}
  1840.  
  1841.  {$ifdef Win32}
  1842.   try { finally }
  1843.  {$endif}
  1844.  
  1845.   s1:= {$ifdef Win32} fSpec
  1846.        {$else}        StrPas(fSpec)
  1847.        {$endif};
  1848.   s2:= {$ifdef Win32} ExpandFileName(ArchName)
  1849.        {$else}        StrPas(ArchName)
  1850.        {$endif};
  1851.  
  1852.  {are we reading from a file?}
  1853.   UseFile := False;
  1854.   i := Pos('/F=', Uppercase(s1));
  1855.   If i > 0 then
  1856.     begin
  1857.       Delete(s1, 1, i+2);
  1858.       UseFile := True;
  1859.       LZRecurseDirs := LZNoRecurse
  1860.     end;
  1861.  
  1862.   if (Length(s1)=0) or (Length(s2)=0) then
  1863.   {$ifdef Win32}
  1864.     RaiseError(EChiefLZError,SInvalidParams);
  1865.   {$else}
  1866.     begin
  1867.       LZDone;
  1868.       Exit
  1869.     end;
  1870.   {$endif}
  1871.  
  1872. {$ifdef Win32}
  1873.  
  1874.   s1 := ExpandFileName(s1);
  1875.   if AnsiCompareText(s1,s2) = 0 then
  1876.     RaiseErrorStr(EChiefLZArchive,SSameFileName,s1);
  1877.  
  1878.   AssignFile(OutFile, s2);
  1879.   Rewrite(OutFile, 1);
  1880.   try { finally }
  1881.     Result := 0;
  1882.  
  1883.     New(jR);
  1884.     try { finally }           
  1885.       Hed.Count := 0;
  1886.       DirCount := 0;
  1887.  
  1888.     { get the filenames for the archive }
  1889.       if UseFile then { - use a LIST file }
  1890.         begin
  1891.           Path := '';
  1892.           AssignFile(t, s1);
  1893.           Reset(t);
  1894.           try { finally }
  1895.             while not EOF(t) do
  1896.               begin
  1897.                 Readln(t,s1);
  1898.                 if (Length(s1)<>0) and
  1899.                    (AnsiCompareText(s1,s2) <> 0) and
  1900.                     FileExists(s1) then
  1901.                   begin
  1902.                   {$IFDEF Debug}
  1903.                     if Hed.Count > MaxChiefLZArchiveSize then
  1904.                       raise EChiefLZDebug.Create('Too many archive files');
  1905.                   {$ENDIF}
  1906.                     if Hed.Count >= MaxChiefLZArchiveSize then
  1907.                       break;
  1908.                     inc(Hed.Count);
  1909.                     with jr^[Hed.Count] do
  1910.                       begin
  1911.                         IsBigDir := False;
  1912.                         BigDirID := 0;
  1913.                         BigCompressed := True;
  1914.                         uBigSizes := fSize(s1);
  1915.                         BigTimes := sfTime(s1);
  1916.                         BigFileVersion := GetFileVersion(s1);
  1917.                         BigNames := s1
  1918.                       end
  1919.                   end {s1 <> s2}
  1920.               end; {not EOF(t)}
  1921.             if Hed.Count = 0 then
  1922.               RaiseError(EChiefLZArchive, SNoValidFileName)
  1923.           finally
  1924.             CloseFile(t)
  1925.           end
  1926.         end
  1927. {
  1928.   We do not have a LIST file, so find filespecs ...
  1929. }
  1930.         else
  1931.           begin
  1932.             Path := ExtractFilePath(s1);
  1933.             fSpecName := ExtractFileName(s1);
  1934.             New(DirArray);
  1935.             try {finally}
  1936.               DirArray^[0] := Path;
  1937.  
  1938.               if LZRecurseDirs <> LZNoRecurse then
  1939. {
  1940.   `Recurse' through subdirectories for files matching the given mask.
  1941.   There are 2 levels of recursion - full recursion and immediate-subdirs...
  1942. }
  1943.               begin
  1944.                 New(DirTimes);
  1945.                 try {finally}
  1946.  
  1947.                   i := 0;
  1948.                   repeat
  1949.                     if (LZRecurseDirs <> LZNoRecurse) and
  1950.                        (FindFirst(DirArray^[i]+'*', faDirs, Dir) = 0) then
  1951.                     try {finally}
  1952.                       repeat
  1953.                         if Dir.Attr and faDirectory <> 0 then
  1954.                           begin
  1955.                             FoundName := GetFoundFileName(Dir);
  1956.                             if (FoundName <> '.') and
  1957.                                (FoundName <> '..') then
  1958.                               begin
  1959.                               {$IFDEF Debug}
  1960.                                 if DirCount > MaxChiefLZDirectories then
  1961.                                   raise EChiefLZDebug.Create('DirArray^ bounds exceeded');
  1962.                               {$ENDIF}
  1963.                                 if DirCount >= MaxChiefLZDirectories then
  1964.                                   break;
  1965.                                 inc(DirCount);
  1966.                                 DirArray^[DirCount] :=
  1967.                                                     DirArray^[i]+FoundName+'\';
  1968.                                 DirTimes^[DirCount] := Dir.Time
  1969.                               end
  1970.                           end
  1971.                       until FindNext(Dir) <> 0
  1972.                     finally
  1973.                       SysUtils.FindClose(Dir)
  1974.                     end;
  1975.  
  1976.                     if i = 0 then
  1977.                       begin
  1978.                         Inc(i);
  1979. {
  1980.             Turn directory-recursion off - have only looked in
  1981.             immediate subdirectories ...
  1982. }
  1983.                         if LZRecurseDirs = LZRecurseOnce then
  1984.                           Dec(LZRecurseDirs)
  1985.                       end
  1986.                     else if not IsFileInDir(DirArray^[i]+fSpecName) then
  1987.                       begin
  1988.                         DirArray^[i] := '';  { Destroy string ... }
  1989.                         Move(DirArray^[i+1],
  1990.                              DirArray^[i],
  1991.                             (DirCount-i)*SizeOf(DirArray^[0]));
  1992.                         Move(DirTimes^[i+1],
  1993.                              DirTimes^[i],
  1994.                             (DirCount-i)*SizeOf(DirTimes^[1]));
  1995. {
  1996.   I think I'm messing too deeply with long strings here... If I am correct,
  1997.   then I need to set the element DirArray[DirCount] to be an empty string
  1998.   WITHOUT TAMPERING WITH THE REFERENCE COUNTS !!! I.e. the element must be
  1999.   typecast to a pointer and set to nil...
  2000. }
  2001.                         Pointer(DirArray[DirCount]) := nil;
  2002.                         Dec(DirCount)
  2003.                       end
  2004.                     else
  2005.                       begin
  2006.                         Inc(Hed.Count);
  2007.                         with jr^[Hed.Count] do
  2008.                           begin
  2009.                             IsBigDir  := True;
  2010.                             BigDirID  := i;
  2011.                             BigTimes  := DirTimes^[i];
  2012. {
  2013.   These two fields irrelevant for directories ...
  2014. }
  2015.                             BigSizes  := 0;
  2016.                             uBigSizes := 0;
  2017. {}
  2018.                             BigFileVersion := '-';
  2019.                             BigNames  := RemoveBackSlash(DirArray^[i])
  2020.                           end;
  2021.                         Inc(i)
  2022.                       end
  2023.  
  2024.                   until i > DirCount
  2025.  
  2026.                 finally
  2027.                   Dispose(DirTimes)
  2028.                 end;
  2029. {
  2030.   Find the parents for each directory ...
  2031. }
  2032.                 DirCountEx := DirCount;
  2033.                 for i := 1 to DirCount do
  2034.                   begin
  2035. {
  2036.   Search for a hole in the directory structure ...
  2037. }
  2038.                     FoundName :=
  2039.                             ExtractFilePath(RemoveBackSlash(DirArray^[i]));
  2040.                     PIndex := GetDirIndex(FoundName,DirArray,DirCountEx);
  2041. {
  2042.   If such a hole exists, we must store headers for all the missing
  2043.   directories between Path and FoundName WORKING FORWARDS, or we'll
  2044.   give some of the directories the wrong parents ...
  2045. }
  2046.                     if PIndex < 0 then
  2047.                       begin
  2048.                         PIndex := 0;
  2049.                         s1 := Path;
  2050.                         repeat
  2051.                           s1 := FirstDirectoryBetween(s1,FoundName);
  2052.                           NewPIndex := GetDirIndex(s1,DirArray,DirCountEx);
  2053.                           if NewPIndex < 0 then
  2054.                             begin
  2055. {
  2056.   Do we have room for another directory ... ?
  2057. }
  2058.                             {$IFDEF Debug}
  2059.                               if DirCountEx > MaxChiefLZDirectories then
  2060.                                 raise EChiefLZDebug.Create('Too many ChiefLZ directories.');
  2061.                             {$ENDIF}
  2062.                               if DirCountEx >= MaxChiefLZDirectories then
  2063.                                 Break;
  2064.  
  2065.                               inc(DirCountEx);
  2066.                               DirArray^[DirCountEx] := s1;
  2067.                               inc(Hed.Count);
  2068.                               with jr^[Hed.Count] do
  2069.                                 begin
  2070.                                   BigNames := RemoveBackSlash(s1);
  2071.                                   BigTimes := NulFileDate;
  2072.                                   IsBigDir := True; 
  2073.                                   BigDirID := DirCountEx;
  2074.                                   BigParentDir := PIndex;
  2075. {
  2076.   These fields irrelevant for directories ...
  2077. }
  2078.                                   BigSizes  := 0;
  2079.                                   uBigSizes := 0;
  2080. {}
  2081.                                   BigFileVersion := '-'
  2082.                                 end;
  2083.                               NewPIndex := DirCountEx
  2084.                             end;
  2085.                           PIndex := NewPIndex
  2086.                         until Length(s1) = Length(FoundName)
  2087.                       end; {PIndex < 0}
  2088. {
  2089.   Now we're sure it exists, store Parent-index for directory i ...
  2090. }
  2091.                     jr^[i].BigParentDir := PIndex
  2092.  
  2093.                   end { 1 <= i <= DirCount }
  2094.               end; { LZRecurseDirs }
  2095. {
  2096.    Look through the directory list (only the ones with files in!) and
  2097.    create an archive of files from them. Note that DirArray^[0] is
  2098.    the Path directory ...
  2099. }
  2100.               for i := 0 to DirCount do
  2101.                 if FindFirst(DirArray^[i]+fSpecName, faFiles, Dir) = 0 then
  2102.                   try { finally }
  2103.                     repeat
  2104.                       s1 := DirArray^[i] + GetFoundFileName(Dir);
  2105.                     {$IFDEF Debug}
  2106.                     { Did not put faDirectory in Attr mask, so
  2107.                       **shouldn't** see any directories ...   }
  2108.                       if Dir.Attr and faDirectory <> 0 then
  2109.                         raise EChiefLZDebug.Create('Found directory when expecting file');
  2110.                     {$ENDIF}
  2111. {
  2112.   Check that we are not trying to archive the output file ...
  2113. }
  2114.                       if AnsiCompareText(s1,s2) <> 0 then
  2115.                         begin
  2116.                         {$IFDEF Debug}
  2117.                           if Hed.Count > MaxChiefLZArchiveSize then
  2118.                             raise EChiefLZDebug.Create('Max archive size exceeded.');
  2119.                         {$ENDIF}
  2120.                           if Hed.Count >= MaxChiefLZArchiveSize then
  2121.                             Break;
  2122.                           inc(Hed.Count);
  2123.                           with jr^[Hed.Count] do
  2124.                             begin
  2125.                               IsBigDir  := False;
  2126.                               BigDirID  := i;
  2127.                               BigCompressed := True;
  2128.                               uBigSizes := Dir.Size;
  2129.                               BigSizes  := Dir.Size;
  2130.                               BigTimes  := Dir.Time;
  2131.                               BigNames  := s1;
  2132.                               BigFileVersion := GetFileVersion(s1);
  2133.                             end
  2134.                         end
  2135.                     until FindNext(Dir) <> 0
  2136.                   finally
  2137.                     SysUtils.FindClose(Dir)
  2138.                   end
  2139.  
  2140.             finally
  2141.               Dispose(DirArray)
  2142.             end
  2143.           end;
  2144.  
  2145.         Hed.Signature := MyLZSignature;
  2146.         MemRec := SizeOf(TLZFileRec)*Hed.Count + SizeOf(TLZCount);
  2147.  
  2148.         {fix the header}
  2149.         GetMem(jr2, MemRec);
  2150.         try { finally }
  2151.  
  2152.           FillChar(jr2^, MemRec, 0);
  2153.           jr2^.Count := Hed.Count;
  2154.           for i := 1 to Hed.Count do
  2155.             with jr2^.Files[i], jr^[i] do
  2156.               begin
  2157.                 IsDir  := IsBigDir;
  2158.                 DirID  := BigDirID;
  2159.                 ParentDir := BigParentDir;
  2160.                 Compressed := BigCompressed;
  2161.                 Sizes  := BigSizes;
  2162.                 uSizes := uBigSizes;
  2163.                 Times  := BigTimes;
  2164.                 FileVersion := BigFileVersion;
  2165.                 Names  := ExtractFileName(BigNames)
  2166.               end;
  2167.         { write the header }
  2168.           BlockWrite(OutFile, Hed.Signature, SizeOf(Hed.Signature));
  2169.                                                      {main header}
  2170.           BlockWrite(OutFile, jr2^, MemRec);         {file headers}
  2171.  
  2172.         { loop through each file }
  2173.           for i := 1+DirCount to Hed.Count do
  2174.             with jr^[i] do
  2175.               begin
  2176.                 AssignFile(InFile,BigNames);
  2177.                 InitReportRec(RepRec, jr^[i]);
  2178.                 BlankRec := RepRec;
  2179.  
  2180.                 FileMode := fmOpenRead; { Win32 only allows 0 <= FileMode <= 2 }
  2181.               {$I-}                     { However, share access is FILE_SHARE_READ }
  2182.                 Reset(InFile, 1);
  2183.               {$I+}
  2184.                 if IOResult <> 0 then    { Exception block generates   }
  2185.                   with jr2^.Files[i] do  { false compiler warning ...  }
  2186.                     begin                { Handle error using IOResult }
  2187.                       Sizes  := 0;
  2188.                       uSizes := 0;
  2189.                       Compressed := False;
  2190.                       Continue
  2191.                     end;
  2192.  
  2193.                 try { finally }
  2194.                { report procedure }
  2195.                   inc(Result);
  2196.                   if Assigned(aProc) then aProc(RepRec,-1);
  2197.                   LZReportProc := aProc;
  2198.                   with jr2^.Files[i] do
  2199.                     if IsChiefLZFile(BigNames) or
  2200.                        IsChiefLZArchive(BigNames) then
  2201.                  { Just copy (compressed) file into archive ... }
  2202.                       begin
  2203.                         Sizes := MyFCopy(InFile,OutFile,
  2204.                                          LZ_UNKNOWN_LENGTH,doReportOnRead);
  2205.                         Compressed := False
  2206.                       end
  2207.                     else
  2208.                  { Compress the file into the archive ... }
  2209.                       Sizes := ArchiveSquash(InFile, OutFile, aProc)
  2210.                 finally
  2211.                   CloseFile(InFile);
  2212.                   if Assigned(aProc) then
  2213.                     begin
  2214.                       RepRec.Names := '';
  2215.                       aProc(RepRec,-2)
  2216.                     end
  2217.                 end
  2218.               end; { 1+DirCount <= i <= Count }
  2219.  
  2220.         { write header again }
  2221.           Seek(OutFile, SizeOf(Hed.Signature));
  2222.           BlockWrite(OutFile, jr2^, MemRec); {file headers}
  2223.  
  2224.         finally
  2225.           FreeMem(jr2, MemRec)
  2226.         end
  2227.  
  2228.     finally
  2229.       Dispose(jr)
  2230.     end
  2231.  
  2232.   finally
  2233.     CloseFile(OutFile)
  2234.   end
  2235.   finally
  2236.     LZDone
  2237.   end;
  2238. {$else}
  2239.  
  2240.   {find path to add to filenames}
  2241.    Path := '';
  2242.    if not UseFile then
  2243.      Path := ExtractFilePath(s1);
  2244.  
  2245.    if Length(Path) = 0 then
  2246.      GetDir(0, Path);
  2247.    Path := AddBackSlash(Uppercase(Path));
  2248.  
  2249.    if Length(ExtractFilePath(s2)) = 0 then
  2250.      Insert(AddBackSlash(GetCurrentDir),s2,1);
  2251.  
  2252.    if Length(ExtractFilePath(s1)) = 0 then
  2253.      Insert(Path,s1,1);
  2254.  
  2255.    s2 := Uppercase(s2);
  2256.    {s1=filespec; s2=archive file}
  2257.  
  2258.    if Uppercase(s1) <> s2
  2259.    then begin
  2260.  
  2261.    Assign(OutFile, s2);
  2262.    Rewrite(OutFile, 1);
  2263.    If IOResult<>0 then
  2264.      LZArchive := -11 {write error}
  2265.    else begin
  2266.  
  2267.    New(jR);
  2268.    if jr = nil then
  2269.    {
  2270.      Error condition ... ???
  2271.    }
  2272.    else begin
  2273.  
  2274.    LZArchive := 0; {no file}
  2275.    Hed.Count := 0;
  2276.    DirCount  := 0;
  2277.  
  2278.    {get the file names for the archive}
  2279.    If UseFile then BEGIN {using a LIST file}
  2280.       Assign(t, s1);
  2281.       Reset(t);
  2282.       If IOResult<>0 then begin
  2283.          LZArchive := -13; {LIST file does not exist}
  2284.          Dispose(jr);
  2285.          Close(OutFile); if IOResult<>0 then;
  2286.          LZDone;
  2287.          Exit
  2288.       end;
  2289.       While not EOF(t) do begin
  2290.         Readln(t, s1);
  2291.         s1 := Uppercase(s1);
  2292.         if (IOResult=0) and (Length(s1)>0)
  2293.             and (s1 <> s2)
  2294.             and FileExists(s1) then
  2295.           begin
  2296.           {$IFDEF Debug}
  2297.             if Hed.Count > MaxChiefLZArchiveSize then
  2298.               RunErrorMessage('Max ChiefLZ archive size exceeded.');
  2299.           {$ENDIF}
  2300.             if Hed.Count >= MaxChiefLZArchiveSize then
  2301.               Break;
  2302.             inc(Hed.Count);
  2303.             with jr^[Hed.Count] do
  2304.               begin
  2305.                 IsBigDir  := False;
  2306.                 BigDirID  := 0;
  2307.                 BigCompressed := True;
  2308.                 uBigSizes := fSize(s1);
  2309.                 BigTimes  := sfTime(s1);
  2310.                 BigNames  := s1;
  2311.                 BigFileVersion := GetFileVersion(s1);
  2312.               end
  2313.           end {s1<>s2}
  2314.       end; {while not eof(t)}
  2315.  
  2316.       Close(t);if IOResult<>0 then;
  2317.  
  2318.       if (Hed.Count = 0) then begin {no file}
  2319.          LZArchive := -14; {no valid file in LIST file}
  2320.          Dispose(jr);
  2321.          Close(OutFile); if IOResult<>0 then;
  2322.          LZDone;
  2323.          Exit
  2324.       end;
  2325.    END
  2326. {
  2327.   We do not have a LIST file, so find fileSpecs ...
  2328. }
  2329.    else
  2330.      begin
  2331.        fSpecName := ExtractFileName(s1);
  2332.        New(DirArray);
  2333.        if DirArray <> nil then
  2334.        begin
  2335.          DirCountEx := 0;
  2336.          DirArray^[0] := @Path;  { REMEMBER - Path is NOT on the Heap! }
  2337.  
  2338.          if LZRecurseDirs <> LZNoRecurse then
  2339. {
  2340.   `Recurse' through subdirectories for files matching the given mask.
  2341.   There are 2 levels of recursion - full recursion and immediate-subdirs...
  2342. }
  2343.          begin
  2344.            New(DirTimes);
  2345.            if DirTimes <> nil then
  2346.            begin
  2347.  
  2348.              i := 0;
  2349.              repeat
  2350.                if LZRecurseDirs <> LZNoRecurse then
  2351.                begin
  2352.              {$ifdef Delphi}
  2353.                if FindFirst(DirArray^[i]^+'*.*',faDirs,Dir) = 0 then
  2354.                begin
  2355.              {$else}
  2356.              {$ifdef Windows}
  2357.                Temp := DirArray^[i]^+'*.*';
  2358.                FindFirst(Str2PChar(Temp),faDirs,Dir);
  2359.              {$else Windows}
  2360.                FindFirst(DirArray^[i]^+'*.*',faDirs,Dir);
  2361.              {$endif Windows}
  2362.                if DosError = 0 then
  2363.              {$endif}
  2364.                repeat
  2365.                {$ifdef TPW}
  2366.                  FoundName := StrPas(Dir.Name);
  2367.                {$endif TPW}
  2368.                  if (Dir.Attr and {$ifdef Windows} faDirectory
  2369.                                   {$else}          Directory
  2370.                                   {$endif} <> 0) and
  2371.                   {$ifdef TPW}
  2372.                     (FoundName <> '.') and (FoundName <> '..')
  2373.                   {$else TPW}
  2374.                     (Dir.Name <> '.') and (Dir.Name <> '..')
  2375.                   {$Endif TPW}
  2376.  
  2377.                  then
  2378.                  begin
  2379.                  {$IFDEF Debug}
  2380.                    if DirCount > MaxChiefLZDirectories then
  2381.                      RunErrorMessage('DirArray^ bounds exceeded.');
  2382.                  {$ENDIF}
  2383.                    if DirCount >= MaxChiefLZDirectories then
  2384.                      break;
  2385.                    inc(DirCount);
  2386.                    {
  2387.                    writeln(DirCount,'=',Dir.Name);
  2388.                    }
  2389.                    DirTimes^[DirCount] := Dir.Time;
  2390.  
  2391.                    {$ifdef TPW}
  2392.                      DirArray^[DirCount] := NewString(DirArray^[i]^+FoundName+'\');
  2393.                    {$else TPW}
  2394.                      DirArray^[DirCount] := NewString(DirArray^[i]^+Dir.Name+'\');
  2395.                    {$endif TPW}
  2396.  
  2397.                    if DirArray^[DirCount] = nil then
  2398.                    {
  2399.                      Error condition ...
  2400.                    };
  2401.                  end;
  2402.              {$ifdef Delphi}
  2403.                until FindNext(Dir) <> 0;
  2404.                SysUtils.FindClose(Dir)
  2405.                end;
  2406.              {$else}
  2407.                  FindNext(Dir)
  2408.                until DosError <> 0;
  2409.              {$endif}
  2410.                end;
  2411.  
  2412.                if i = 0 then
  2413.                  begin
  2414.                    Inc(i);
  2415. {
  2416.             Turn directory-recursion off - have only looked in
  2417.             immediate subdirectories ...
  2418. }
  2419.                    if LZRecurseDirs = LZRecurseOnce then
  2420.                      Dec(LZRecurseDirs)
  2421.                  end
  2422.  
  2423.                else if not IsFileInDir(DirArray^[i]^+fSpecName) then
  2424.                  begin
  2425.                    DisposeString(DirArray^[i]);
  2426.                    Move(DirArray^[i+1],DirArray^[i],
  2427.                                               (DirCount-i)*SizeOf(PString));
  2428.                    Move(DirTimes^[i+1],DirTimes^[i],
  2429.                                               (DirCount-i)*SizeOf(LongInt));
  2430.                    DirArray^[DirCount] := nil;
  2431.                    Dec(DirCount)
  2432.                  end
  2433.  
  2434.                else
  2435.                  begin
  2436.                    Inc(Hed.Count);
  2437.                    with jr^[Hed.Count] do
  2438.                      begin
  2439.                        IsBigDir  := True;
  2440.                        BigDirID  := i;
  2441.                        BigCompressed := False;
  2442.                        uBigSizes := 0;
  2443.                        BigSizes  := 0;
  2444.                        BigTimes  := DirTimes^[i];
  2445.                        BigFileVersion := '-';
  2446.                        BigNames  := RemoveBackSlash(DirArray^[i]^)
  2447.                      end;
  2448.                    Inc(i)
  2449.                  end;
  2450.  
  2451.              until i > DirCount;
  2452.  
  2453.              Dispose(DirTimes)
  2454.            end; {DirTimes <> nil}
  2455. {
  2456.   Find the parents for each directory ...
  2457. }
  2458.          DirCountEx := DirCount;
  2459.          for i := 1 to DirCount do
  2460.            begin
  2461. {
  2462.   Search for a hole in the directory structure ...
  2463. }
  2464.              FoundName := ExtractFilePath(RemoveBackSlash(DirArray^[i]^));
  2465.              PIndex := GetDirIndex(FoundName, DirArray, DirCountEx);
  2466. {
  2467.   If such a hole exists, we must store headers for all the missing
  2468.   directories between Path and FoundName WORKING FORWARDS, or we'll
  2469.   give some of the directories the wrong parents ...
  2470. }
  2471.              if PIndex < 0 then
  2472.                begin
  2473.                  PIndex := 0;
  2474.                  s1 := Path;
  2475.                  repeat
  2476.                    s1 := FirstDirectoryBetween(s1,FoundName);
  2477.  
  2478.                    NewPIndex := GetDirIndex(s1,DirArray,DirCountEx);
  2479.                    if NewPIndex < 0 then
  2480.                      begin
  2481. {
  2482.   Do we have room for another directory ... ?
  2483. }
  2484.                      {$IFDEF Debug}
  2485.                        if DirCountEx > MaxChiefLZDirectories then
  2486.                          RunErrorMessage('Too many ChiefLZ directories.');
  2487.                      {$ENDIF}
  2488.                        if DirCountEx >= MaxChiefLZDirectories then
  2489.                          Break;
  2490.  
  2491.                        inc(DirCountEx);
  2492.                        DirArray^[DirCountEx] := NewString(s1);
  2493.                        inc(Hed.Count);
  2494.                        with jr^[Hed.Count] do
  2495.                          begin
  2496.                            BigNames := RemoveBackSlash(s1);
  2497.                            BigTimes := NulFileDate;
  2498.                            IsBigDir := True;
  2499.                            BigDirID := DirCountEx;
  2500.                            BigParentDir := PIndex;
  2501.                            BigSizes  := 0;
  2502.                            uBigSizes := 0;
  2503.                            BigFileVersion := '-';
  2504.                          end;
  2505.                        NewPIndex := DirCountEx
  2506.                      end;
  2507.                    PIndex := NewPIndex
  2508.                  until Length(s1) = Length(FoundName)
  2509.                end; { PIndex < 0 }
  2510. {
  2511.   Now we're sure it exists, store Parent-index for directory i ...
  2512. }
  2513.              jr^[i].BigParentDir := PIndex
  2514.  
  2515.            end { 1 <= i <= DirCount }
  2516.  
  2517.          end; { LZRecurseDirs }
  2518. {
  2519.   Look through the directory list and create an archive of files from them...
  2520.   Note that DirArray[0]^ is the Path directory ...
  2521. }
  2522.          for i := 0 to DirCount do
  2523.          begin
  2524.          {$ifdef Delphi}
  2525.            if FindFirst(DirArray^[i]^+fSpecName,faFiles,Dir) = 0 then
  2526.          {$else Delphi}
  2527.          {$ifdef Windows}
  2528.            Temp := DirArray^[i]^+fSpecName;
  2529.            FindFirst(Str2PChar(Temp),faFiles,Dir);
  2530.          {$else Windows}
  2531.            FindFirst(DirArray^[i]^+fSpecName,faFiles,Dir);
  2532.          {$endif Windows}
  2533.            if DosError = 0 then
  2534.          {$endif Delphi}
  2535.            repeat
  2536.            {$ifdef TPW}
  2537.              s1 := DirArray^[i]^+StrPas(Dir.Name);
  2538.            {$else TPW}
  2539.              s1 := DirArray^[i]^+Dir.Name;
  2540.            {$endif TPW}
  2541.  
  2542.            {$IFDEF Debug}
  2543.            { Did not put faDirectory in Attr mask, so *shouldn't*
  2544.              see any directories ... }
  2545.              if Dir.Attr and {$ifdef Windows} faDirectory
  2546.                              {$else}          Directory
  2547.                              {$endif} <> 0 then
  2548.                RunErrorMessage('Found directory when expecting file');
  2549.            {$ENDIF}
  2550. {
  2551.   Check that we are not trying to archive the output file ...
  2552. }
  2553.              if Uppercase(s1) <> s2 then
  2554.              begin
  2555.              {$IFDEF Debug}
  2556.                if Hed.Count > MaxChiefLZArchiveSize then
  2557.                  RunErrorMessage('Max archive size exceeded');
  2558.              {$ENDIF}
  2559.                if Hed.Count >= MaxChiefLZArchiveSize then
  2560.                  Break;
  2561.                inc(Hed.Count);
  2562.                with jr^[Hed.Count] do
  2563.                  begin
  2564.                    IsBigDir      := False;
  2565.                    BigDirID      := i;
  2566.                    BigCompressed := True;
  2567.                    uBigSizes     := Dir.Size;
  2568.                    BigSizes      := Dir.Size;
  2569.                    BigTimes      := Dir.Time;
  2570.                    BigNames      := s1;
  2571.                    BigFileVersion := GetFileVersion(s1);
  2572.                  end
  2573.              end;
  2574.          {$ifdef Delphi}
  2575.            until FindNext(Dir) <> 0;
  2576.            SysUtils.FindClose(Dir);
  2577.          {$else Delphi}
  2578.              FindNext(Dir);
  2579.            until DosError <> 0;
  2580.          {$endif Delphi}
  2581.          end;
  2582.  
  2583.          for i := 1 to DirCountEx do
  2584.            DisposeString(DirArray^[i]);
  2585.          Dispose(DirArray)
  2586.  
  2587.        end; { DirArray <> nil }
  2588.      end; { NOT UseFile }
  2589.  
  2590.    Hed.Signature := MyLZSignature;
  2591.    MemRec := SizeOf(TLZFileRec)*Hed.Count + SizeOf(TLZCount);
  2592.  
  2593.    {fix the header}
  2594.    GetMem(jr2, MemRec);
  2595.    if jr2 = nil then
  2596.    {
  2597.      Error condition ...???
  2598.    };
  2599.    FillChar(jr2^, MemRec, #0);
  2600.    jr2^.Count := Hed.Count;
  2601.    for i := 1 to Hed.Count do
  2602.      with jr2^.Files[i], jr^[i] do
  2603.        begin
  2604.          IsDir  := IsBigDir;
  2605.          DirID  := BigDirID;
  2606.          ParentDir := BigParentDir;
  2607.          Compressed := BigCompressed;
  2608.          Sizes  := BigSizes;
  2609.          uSizes := uBigSizes;
  2610.          Times  := BigTimes;
  2611.          FileVersion := BigFileVersion;
  2612.          Names  := ExtractFileName(BigNames);
  2613.        end;
  2614.  
  2615.   {write the header}
  2616.   BlockWrite(OutFile, Hed.Signature, SizeOf(Hed.Signature)); {main header}
  2617.   BlockWrite(OutFile, jr2^, MemRec); {file headers}
  2618.   If IOResult<>0 then
  2619.     LZArchive := -12 {header write error}
  2620.   else begin
  2621.  
  2622.   LZArchive := -13; {other write error}
  2623.   LZTot := 0;
  2624.  
  2625.   {loop through each file}
  2626.   for i := 1+DirCount to Hed.Count do
  2627.     with jr^[i] do
  2628.       begin
  2629.         InitReportRec(RepRec, jr^[i]);
  2630.         BlankRec := RepRec;
  2631.         Assign(InFile, BigNames);
  2632.         OldFMode := FileMode;
  2633. {
  2634.   This choice of FileMode will cause Reset() to fail unless LZArchive
  2635.   has *EXCLUSIVE WRITE-ACCESS* to the file. This is what we want, as
  2636.   otherwise the file might change midway through the archive process.
  2637. }
  2638.         FileMode := (fmOpenRead or fmShareDenyWrite);
  2639.         Reset(InFile, 1);
  2640.         FileMode := OldFMode;
  2641.         if IOResult <> 0 then
  2642.           with jr2^.Files[i] do
  2643.             begin                { Could not open file- insert nul }
  2644.               Sizes  := 0;       { entry into the LZ-Archive.      }
  2645.               uSizes := 0;
  2646.               Compressed := False;
  2647.               Continue
  2648.             end;
  2649.  
  2650.        {report procedure }
  2651.         if Assigned(aProc) then aProc(RepRec, -1);
  2652.  
  2653.         inc(LZTot);
  2654.         LZReportProc := aProc;
  2655.  
  2656.         with jr2^.Files[i] do
  2657.           begin
  2658.             if (IsChiefLZArchive(Str2PChar(BigNames)))
  2659.               or (IsChiefLZFile(Str2PChar(BigNames))) then
  2660.               begin
  2661.                 l := MyFCopy(InFile,OutFile,
  2662.                               LZ_UNKNOWN_LENGTH,doReportOnRead);
  2663.                 Compressed := False
  2664.               end
  2665.             else
  2666.               l := ArchiveSquash(InFile, OutFile, aProc);
  2667.             Sizes := l
  2668.           end{with jr2^};
  2669.  
  2670.         Close(InFile);if IOResult<>0 then;
  2671.         if Assigned(aPRoc) then
  2672.           begin
  2673.             RepRec.Names := '';
  2674.             aProc(RepRec, -2)
  2675.           end
  2676.       end; {With jr^, DirCount+1 <= i <= Count}
  2677.  
  2678.    LZArchive := LZTot;
  2679.  
  2680.    {rewrite header again}
  2681.    Seek(OutFile, SizeOf(Hed.Signature));
  2682.    BlockWrite(OutFile, jr2^, MemRec); {file headers}
  2683.    end;
  2684.  
  2685.    FreeMem(jr2, MemRec);
  2686.  
  2687.    Dispose(jr);
  2688.    end; { jr <> nil }
  2689.  
  2690.    Close(OutFile);if IOResult<>0 then;
  2691.    end; { IOResult = 0 }
  2692.    end; { Uppercase(s1) = s2 }
  2693.    LZDone;
  2694. {$endif}
  2695. End;
  2696.  
  2697. {/////////////////////////////////////////////////////////}
  2698. {/////////////////////////////////////////////////////////}
  2699. {/////////////////////////////////////////////////////////}
  2700. {/////////////////////////////////////////////////////////}
  2701. Function LZDearchive(ArchName: {$ifdef Win32} string
  2702.                                {$else}        PChar
  2703.                                {$endif};
  2704.                     {$ifdef Win32} DefDir: string
  2705.                     {$else} const aDefDir: PChar
  2706.                     {$endif};
  2707.                      LZQuestion: TLZQuestionFunc;
  2708.                      aProc:      TLZReportProc;
  2709.                      aRename:    TLZRenameFunc):LongInt;
  2710. {$ifdef aDLL} {$ifdef Win32} stdcall
  2711.               {$else Win32}  export
  2712.               {$endif Win32};
  2713. {$endif aDLL}
  2714. {
  2715.   Local function to determine user's request ...
  2716. }
  2717. function UserRequestsRename(var FName: TLZPathStr): boolean;
  2718. var
  2719.   Path,
  2720.   TempName: string;
  2721. {$ifndef Delphi}
  2722.   Result:   boolean;
  2723. {$endif}
  2724. begin
  2725.   if not Assigned(aRename) then
  2726.     UserRequestsRename := False
  2727.   else
  2728.     begin
  2729.       TempName := FName;
  2730.       Path := ExtractFilePath(TempName);
  2731.       repeat
  2732.         Result := aRename(TempName);
  2733.         if not Result then
  2734.         {$ifdef Delphi}
  2735.           Exit;
  2736.         {$else}
  2737.           begin
  2738.             UserRequestsRename := false;
  2739.             Exit
  2740.           end;
  2741.         {$endif}
  2742.          if Length(ExtractFilePath(TempName)) = 0 then
  2743.            Insert(Path,TempName,1)
  2744.        {$ifdef Delphi}
  2745.          else
  2746.            TempName := ExpandFileName(TempName)
  2747.        {$endif}
  2748.       until not FileExists(TempName);
  2749.       FName := TempName;
  2750.     {$ifndef Delphi}
  2751.       UserRequestsRename := Result
  2752.     {$endif}
  2753.     end
  2754. end;
  2755.  
  2756. VAR
  2757. SrcFile,
  2758. DestFile:file;
  2759. TempFile:file;
  2760.  
  2761. LZFilePos: LongInt;
  2762. f        : TLZHeader;
  2763. RepRec   : TLZReportRec;
  2764. BigMemRec,
  2765. MemRec   : TLZSSWord;
  2766. Hed      : TLZArchiveHeader;
  2767. i        : Integer;
  2768.  
  2769. {$ifdef Win32}
  2770. TempName: string;
  2771. {$else}
  2772. BRead   : Integer;
  2773. OldFMode: byte;
  2774. Total   : LongInt;
  2775. TempName,
  2776. DefDir,Source: string[128];
  2777. {$endif}
  2778. DirArray: PLZDirArray;
  2779. DirCount: Integer;
  2780.  
  2781. begin
  2782.    {$ifdef aDLL}
  2783.      if IsLZInitialized then
  2784.      {$ifdef Win32}
  2785.        RaiseError(EChiefLZDLL,SBusyChief);
  2786.      {$else}
  2787.        begin
  2788.          LZDearchive := -20; {busy}
  2789.          Exit
  2790.        end;
  2791.      {$endif}
  2792.    {$endif aDLL}
  2793.  
  2794.    if not IsChiefLZArchive(ArchName) then
  2795.    {$ifdef Win32}
  2796.      RaiseErrorStr(EChiefLZArchive,SInvalidArchive,ArchName);
  2797.    {$else}
  2798.      begin
  2799.        LZDearchive := -30; {bad archive}
  2800.        Exit
  2801.      end;
  2802.    {$endif}
  2803.  
  2804.    {$ifdef Win32}
  2805.  
  2806.    {target directory}
  2807.    if Length(DefDir) = 0 then
  2808.      GetDir(0,DefDir)  // This directory MUST exist!
  2809.    else
  2810.      begin
  2811.        DefDir := ExpandFileName(DefDir);
  2812.        if not DirectoryExists(DefDir) then
  2813.          try
  2814.            MkDir(DefDir)
  2815.          except
  2816.            RaiseErrorStr(EChiefLZArchive,SBadDirectory,DefDir)
  2817.          end              // Delphi will never return from RaiseErrorStr()
  2818.      end;
  2819.  
  2820.    DefDir := AddBackSlash(DefDir);
  2821.  
  2822.    {source file}
  2823.    ArchName := ExpandFileName(ArchName);
  2824.  
  2825.    AssignFile(SrcFile, ArchName);
  2826.    FileMode := fmOpenRead; { Win32 only allows 0 <= FileMode <= 2 }
  2827.    Reset(SrcFile, 1);      { However, share access is FILE_SHARE_READ }
  2828.    try { finally }
  2829.  
  2830.      BlockRead(SrcFile, Hed, SizeOf(Hed));
  2831.      Result := Hed.Count;
  2832.      MemRec := SizeOf(TLZFileRec)*Hed.Count + SizeOf(TLZCount);
  2833.      BigMemRec := SizeOf(TLZBigFileRec)*Hed.Count;
  2834.      GetMem(jr, BigMemRec);
  2835.      try { except }
  2836.        Initialize(jr^[1], Hed.Count); { jr^ contains long strings...!!! }
  2837.        try { finally }
  2838.  
  2839.          GetMem(jr2, MemRec);
  2840.          try { finally }
  2841.            BlockRead(SrcFile, jr2^.Files[1], MemRec-SizeOf(TLZCount));
  2842.            jr2^.Count := Hed.Count;
  2843.  
  2844.            New(DirArray);
  2845.            try { finally }
  2846.  
  2847.              DirCount := 0;
  2848.              DirArray^[0] := DefDir;
  2849.              try { except }
  2850.                for i := 1 to Hed.Count do
  2851.                  with jr^[i], jr2^.Files[i] do
  2852.                    begin
  2853. {
  2854.   IMPORTANT POINT: This algorithm depends on having all of the directory entries
  2855.   listed BEFORE the file entries in the archive header ...
  2856. }
  2857.                      if IsDir then
  2858.                        begin
  2859.                          inc(DirCount);
  2860.                          BigNames := DefDir + GetFullLZName(jr2^,i);
  2861.                          CreatePath(BigNames);
  2862.                      { report directory creation using archive entry info }
  2863.                          if Assigned(aProc) then
  2864.                            begin
  2865.                              InitReportRec(RepRec, jr^[i]);
  2866.                              aProc(RepRec, -1);
  2867.                              RepRec.Names := '';
  2868.                              aProc(RepRec, -2)
  2869.                            end;
  2870.                          DirArray^[i] := BigNames + '\'
  2871.                        end
  2872.                      else
  2873.                        BigNames := DirArray^[DirID] + Names;
  2874.  
  2875.                      IsBigDir  := IsDir;
  2876.                      BigDirID  := DirID;
  2877.                      BigParentDir := ParentDir;
  2878.                      BigCompressed := Compressed;
  2879.                      BigSizes  := Sizes;
  2880.                      uBigSizes := uSizes;
  2881.                      BigTimes  := Times;
  2882.                      BigFileVersion := FileVersion
  2883.  
  2884.                    end {with jr^}
  2885.              except
  2886.                on EInOutError do
  2887.                  RaiseErrorStr(EChiefLZArchive,SBadDirectory,DirArray^[DirCount])
  2888.              end
  2889.  
  2890.            finally
  2891.              Dispose(DirArray)
  2892.            end
  2893.          finally
  2894.            FreeMem(jr2, MemRec)
  2895.          end;
  2896.  
  2897.          New(Buf);
  2898.          try { finally }
  2899.            LZFilePos := FilePos(SrcFile);
  2900.  
  2901.          { temp file }
  2902.            TempName := GetTempChiefFileName; { This call CREATES a file on disc ... }
  2903.            AssignFile(TempFile, TempName);   { ... and this links the file to a Pascal var }
  2904. {
  2905.    If premature EOF, archive is corrupt... This will trigger
  2906.    an exception - handled (and re-raised) below.
  2907. }
  2908.            for i := 1+DirCount to Hed.Count do
  2909.              with jr^[i] do
  2910.                begin {normal file - try to extract}
  2911.                  InitReportRec(RepRec, jr^[i]); {stuff inside the archive}
  2912.                  BlankRec := RepRec;
  2913. {
  2914.   This file was STORED compressed; just copy it out ...
  2915. }
  2916.                  if not BigCompressed then
  2917.                    begin
  2918. {
  2919.   ... ensuring this stored LZ file will not overwrite SrcFile ...
  2920. }
  2921.                      if ( (AnsiCompareText(ArchName,BigNames)<>0)
  2922.                             or UserRequestsRename(BigNames) ) then
  2923. {
  2924.   ...AND checking that the file doesn't already exist ...
  2925. }
  2926.                        if FileExists(BigNames) and Assigned(LZQuestion) then
  2927.                          case LZQuestion(RepRec,BigNames) of
  2928.                            LZQuit: begin
  2929.                                      LZDearchive := Pred(i);
  2930.                                      Break     { User requests Abort!! }
  2931.                                    end;
  2932. {
  2933.   Now the mundane matters - copy out the stored file ...
  2934. }
  2935.                            LZYes: begin
  2936.                                     AssignFile(DestFile, BigNames);
  2937.                                     Rewrite(DestFile,1);
  2938.                                     try { finally }
  2939.                                       if Assigned(aProc) then
  2940.                                         aProc(RepRec,-1);
  2941.                                       LZReportProc := aProc;
  2942.                                       MyFCopy(SrcFile,DestFile,
  2943.                                               BigSizes,doReportOnWrite)
  2944.                                     finally
  2945.                                       CloseFile(DestFile);
  2946.                                       if Assigned(aProc) then
  2947.                                         aProc(RepRec,-2)
  2948.                                     end
  2949.                                   end
  2950.                          end
  2951.                    end
  2952. {
  2953.   This file was compressed into the archive- it needs expanding ...
  2954. }
  2955.                  else
  2956.                    begin
  2957.                      Rewrite(TempFile,1);  // (Re?)open the temp file ... (wiping contents)
  2958.                      try { finally }
  2959.                       { write header ... }
  2960.                        with f do
  2961.                          begin
  2962.                            Signature := ChiefLZSig;
  2963.                            fName     := ExtractFileName(BigNames);
  2964.                            uSize     := uBigSizes;
  2965.                            cSize     := BigSizes;
  2966.                            fTime     := BigTimes;
  2967.                            Version   := BigFileVersion
  2968.                          end;
  2969.                        BlockWrite(TempFile, f, SizeOf(f));
  2970. (*
  2971.                        j := 0;
  2972.                        repeat
  2973.                          BRead := Min(BigSizes-j, SizeOf(Buf^));
  2974.        { If the file is shorter than it should be, raise IO-Exception }
  2975.                          BlockRead(SrcFile, Buf^, BRead);
  2976.        { If the output disc runs out of space, raise IO-Exception }
  2977.                          BlockWrite(TempFile, Buf^, BRead);
  2978.                          inc(j, BRead)
  2979.                        until (j >= BigSizes);
  2980. *)
  2981.                        LZReportProc := nil;
  2982.                        MyFCopy(SrcFile, TempFile, BigSizes, doReportOnWrite)
  2983.  
  2984.                      finally
  2985.                        CloseFile(TempFile)
  2986.                      end;
  2987.  
  2988.                    { decompress the temporary file ... }
  2989.                      try
  2990.                        LZDecompress(TempName,BigNames,LZQuestion,aProc)
  2991.                      except
  2992.                        on EAbort do  { Catch silent exception...    }
  2993.                          begin       { -Stop dearchiving files NOW! }
  2994.                            LZDearchive := Pred(i);
  2995.                            Break
  2996.                          end
  2997.                      end
  2998.                    end;
  2999.  
  3000.               { goto location of next file in archive ... }
  3001.                  inc(LZFilePos, BigSizes);
  3002.                  Seek(SrcFile, LZFilePos)
  3003.                end; { 1+DirCount <= i <= Count }
  3004.  
  3005.            Erase(TempFile)  // Delete the temporary file ...
  3006.  
  3007.          finally
  3008.            Dispose(Buf)
  3009.          end
  3010.        finally
  3011.          Finalize(jr^[1], Hed.Count); // jr^ contains long strings ...!
  3012.          FreeMem(jr, BigMemRec)
  3013.        end
  3014.      except
  3015.        on E: EInOutError do  // Re-raise the exception as something
  3016.          begin               //   more obvious.
  3017.            if E.ErrorCode = 100 then  // `Read beyond EOF'
  3018.              RaiseErrorStr(EChiefLZArchive,SCorruptArchive,ArchName);
  3019.            raise             // Different IO-Error, so re-raise it to next handler
  3020.          end
  3021.      end
  3022.    finally
  3023.      CloseFile(SrcFile)
  3024.    end
  3025.  
  3026.    {$else}
  3027.  
  3028.    {target directory}
  3029.    DefDir := StrPas(aDefDir);
  3030.    if Length(DefDir) = 0 then
  3031.      GetDir(0, DefDir)       { This directory MUST exist! }
  3032.    else if not DirectoryExists(DefDir) then
  3033.      begin
  3034.        MkDir(DefDir);
  3035.        If IOResult <> 0 then
  3036.        begin
  3037.          LZDearchive := -31; {bad directory}
  3038.          Exit
  3039.        end
  3040.      end;
  3041.  
  3042.    DefDir := AddBackSlash(DefDir);
  3043.  
  3044.    TempName := StrPas(ArchName);
  3045.    Source := ExtractFilePath(TempName);
  3046.    TempName := ExtractFileName(TempName);
  3047.    if Length(Source)=0 then
  3048.      GetDir(0, Source);
  3049.    Source := AddBackSlash(Source) + TempName;
  3050.  
  3051.    LZDearchive := -1; {open error}
  3052.    Assign(SrcFile, Source{StrPas(ArchName)});
  3053.    OldFMode := FileMode;
  3054. {
  3055.   Open archive file: we require Read-access, don't need Write-access,
  3056.   and *INSIST* that no one else can write to it (i.e. corrupt it)
  3057.   until we're done ...
  3058. }
  3059.    FileMode := (fmOpenRead or fmShareDenyWrite);
  3060.    Reset(SrcFile, 1);
  3061.    FileMode := OldFMode;
  3062.    If IOResult = 0 then
  3063.    begin
  3064.  
  3065.    LZDearchive := -2; {open error}
  3066.    BlockRead(SrcFile, Hed, SizeOf(Hed));
  3067.    if IOResult = 0 then
  3068.    begin
  3069.  
  3070.    MemRec := SizeOf(TLZFileRec)*Hed.Count + SizeOf(TLZCount);
  3071.    BigMemRec := SizeOf(TLZBigFileRec)*Hed.Count;
  3072.  
  3073.    GetMem(jr, BigMemRec);
  3074.    if jr = nil then
  3075. {
  3076.   Error condition ...
  3077. }
  3078.   else begin
  3079.  
  3080.   GetMem(jr2, MemRec);
  3081.   if jr2 <> nil then
  3082.   begin
  3083.  
  3084.    {error reading header}
  3085.   BlockRead(SrcFile, jr2^.Files[1], MemRec-SizeOf(TLZCount));
  3086.   if IOResult<>0 then begin
  3087.      Close(SrcFile); { Reset() Ok; hence Close() must succeed. }
  3088.      FreeMem(jr2, MemRec);
  3089.      FreeMem(jr, BigMemRec);
  3090.      Exit
  3091.   end;
  3092.   jr2^.Count := Hed.Count;
  3093.  
  3094.   DirCount := 0;
  3095.   New(DirArray);
  3096.   if DirArray <> nil then
  3097.   begin
  3098.  
  3099.     DirArray^[0] := @DefDir; { This string is NOT on the heap!!! }
  3100.  
  3101.     for i := 1 to Hed.Count do
  3102.       with jr^[i], jr2^.Files[i] do
  3103.         begin
  3104.  
  3105.           if IsDir then
  3106.             begin
  3107.               Inc(DirCount);
  3108.               BigNames := DefDir + GetFullLZName(jr2^,i);
  3109.               DirArray^[i] := NewString(BigNames+'\')
  3110.             end
  3111.           else
  3112.             BigNames := DirArray^[DirID]^ + Names;
  3113.  
  3114.           IsBigDir  := IsDir;
  3115.           BigDirId  := DirID;
  3116.           BigParentDir := ParentDir;
  3117.           BigCompressed := Compressed;
  3118.           BigSizes  := Sizes;
  3119.           uBigSizes := uSizes;
  3120.           BigTimes  := Times;
  3121.           BigFileVersion := FileVersion
  3122.  
  3123.         end{with jr^[i]};
  3124.  
  3125.      for i := 1 to DirCount do
  3126.        DisposeString(DirArray^[i]);
  3127.      Dispose(DirArray);
  3128.  
  3129.   end; {DirArray<>nil}
  3130.  
  3131.   FreeMem(jr2, MemRec)
  3132.   end; {jr2<>nil}
  3133. {
  3134.   This code placed here to help reduce the amount of clean-up that must be
  3135.   done in case of an error.
  3136. }
  3137.   for i := 1 to DirCount do
  3138.     begin
  3139.       if CreatePath(jr^[i].BigNames) < 0 then
  3140.         begin
  3141.           LZDearchive := -31;
  3142.           FreeMem(jr, BigMemRec);
  3143.           Close(SrcFile); { Reset() Ok; hence Close() must succeed. }
  3144.           Exit
  3145.         end;
  3146.       if Assigned(aProc) then
  3147.       { report directory-creation using archive-entry information }
  3148.         begin
  3149.           InitReportRec(RepRec, jr^[i]);
  3150.           aProc(RepRec, -1);
  3151.           RepRec.Names := '';
  3152.           aProc(RepRec, -2)
  3153.         end
  3154.     end;
  3155.  
  3156.   LZFilePos := FilePos(SrcFile);
  3157.   New(Buf);
  3158.   if Buf = nil then
  3159.   {
  3160.      Error condition ...???
  3161.   }
  3162.   else begin
  3163.  
  3164.   {error processing file}
  3165.   LZDearchive := 0;
  3166.  
  3167.   {temp file}
  3168. {
  3169.   Str2PChar() works by appending #0 to string, and then returning address
  3170.   of string[1].
  3171. }
  3172.   TempName := DefDir;
  3173.   if not GetTempChiefFileName(Str2PChar(TempName)) then
  3174.     TempName := DefDir + 'CHF$$$.$$$'
  3175.   else
  3176.     TempName[0] := chr(StrLen(@TempName[1])); { adjust length byte }
  3177.   Assign(TempFile, TempName);
  3178.  
  3179.   for i := DirCount+1 to Hed.Count do
  3180.     with jr^[i] do
  3181.       begin {normal file - try to extract}
  3182.         InitReportRec(RepRec, jr^[i]); { stuff inside the archive }
  3183.         BlankRec := RepRec;
  3184. {
  3185.   This file was STORED compressed; just copy it out ...
  3186. }
  3187.         if not BigCompressed then
  3188.         begin
  3189. {
  3190.   ... ensuring this stored LZ file will not overwrite SrcFile ...
  3191. }
  3192.           if ( (Uppercase(Source) <> Uppercase(BigNames)) or
  3193.                UserRequestsRename(BigNames) ) then
  3194. {
  3195.   ...AND checking that the file doesn't already exist ...
  3196. }
  3197.             if FileExists(BigNames) and Assigned(LZQuestion) then
  3198.               case LZQuestion(RepRec,BigNames) of
  3199.                 LZQuit: begin
  3200.                           LZDearchive := Pred(i); { User requested Abort! }
  3201.                           Break
  3202.                         end;
  3203. {
  3204.   Now the mundane matters - copy out the stored file ...
  3205. }
  3206.                 LZYes : begin
  3207.                           Assign(DestFile, BigNames);
  3208.                           Rewrite(DestFile, 1);
  3209.                           if IOResult=0 then begin
  3210.                             LZReportProc := aProc;
  3211.                             if Assigned(aProc) then aProc(RepRec, -1);
  3212.                             MyFCopy(SrcFile,DestFile,
  3213.                                      BigSizes,doReportOnWrite);
  3214.                             Close(DestFile);
  3215.                             if IOResult<>0 then;
  3216.                             if Assigned(aProc) then
  3217.                               begin
  3218.                                 RepRec.Names := '';
  3219.                                 aProc(RepRec, -2)
  3220.                               end
  3221.                           end
  3222.                         end
  3223.               end
  3224.         end
  3225.       else begin (* Is compressed ... *)
  3226.  
  3227.       Rewrite(TempFile, 1);
  3228.       If IOResult <> 0 then begin
  3229.         LZDearchive := -200; {big error}
  3230.         Break
  3231.       end;
  3232.  
  3233.     {write header}
  3234.       With f do begin
  3235.         fName := ExtractFileName(BigNames);
  3236.         Signature := ChiefLZSig;
  3237.         uSize     := uBigSizes;
  3238.         cSize     := BigSizes;
  3239.         fTime     := BigTimes;
  3240.         Version   := BigFileVersion;
  3241.       end;
  3242.  
  3243.       BlockWrite(TempFile, f, SizeOf(f)); {write header}
  3244.       If IOResult <> 0 then begin
  3245.         Close(TempFile); { No possible error; no buffered IO, Rewrite() OK. }
  3246.         Break
  3247.       end;
  3248.  
  3249.       Total := 0;
  3250.       repeat
  3251.         BRead := Min(BigSizes-Total, SizeOf(Buf^));
  3252.    { If the file is shorter than it should be, IO-Error }
  3253.         BlockRead(SrcFile, Buf^, BRead);
  3254.         if IOResult = 0 then
  3255.           begin
  3256.    { If the output disc runs out of space, IO-Error }
  3257.             BlockWrite(TempFile, Buf^, BRead);
  3258.             if IOResult = 0 then
  3259.               begin
  3260.                 inc(Total, BRead);
  3261.                 Continue
  3262.               end
  3263.           end;
  3264.    { Error-handling: clean-up code ... }
  3265.         Close(TempFile); if IOResult <> 0 then;
  3266.         Close(SrcFile);  { Reset() Ok; hence Close() must succeed. }
  3267.         FreeMem(jr, BigMemRec);
  3268.         Dispose(Buf);
  3269.         Exit
  3270.       until (Total >= BigSizes);
  3271.  
  3272.       Close(TempFile); if IOResult<>0 then;
  3273.  
  3274.     {decompress the temporary file}
  3275.       if LZDecompress(Str2PChar(TempName),Str2PChar(BigNames),
  3276.                       LZQuestion,aProc) = -150 then
  3277.         begin                      { User requested Abort !! }
  3278.           Erase(TempFile); if IOResult <> 0 then;
  3279.           LZDearchive := Pred(i);
  3280.           Break
  3281.         end
  3282.  
  3283.     end;
  3284.  
  3285.     LZDearchive := i;
  3286.  
  3287.     {goto location of next file in archive}
  3288.     Inc(LZFilePos, BigSizes);
  3289.     Seek(SrcFile, LZFilePos);
  3290.     If IOResult <> 0 then
  3291.       Break;
  3292.  
  3293.     Erase(TempFile);if IOResult<>0 then;
  3294.  
  3295.   end; { DirCount+1 <= i <= Count) }
  3296.  
  3297.   Dispose(Buf);
  3298.   end; { Buf <> nil }
  3299.  
  3300.   FreeMem(jr, BigMemRec);
  3301.   end; { jr <> nil ... }
  3302.  
  3303.   end; { IOResult = 0 after BlockRead(SrcFile,... }
  3304.  
  3305.   Close(SrcFile); { Reset() Ok; hence Close() must succeed. }
  3306.  
  3307.   end; { IOResult = 0 after Reset(SrcFile,1) }
  3308. {$endif}
  3309. End;
  3310.  
  3311. {/////////////////////////////////////////////////////////}
  3312. {/////////////////////////////////////////////////////////}
  3313. Function LZCompressEx(const {$ifdef Win32} Name:  string
  3314.                             {$else}        aName: PChar
  3315.                             {$endif};
  3316.                       ReplaceQuestion:TLZQuestionFunc;
  3317.                       aProc:TLZReportProc): LongInt;
  3318. {$ifdef aDLL} {$ifdef Win32} stdcall
  3319.               {$else Win32}  export
  3320.               {$endif Win32};
  3321. {$endif aDLL}
  3322.  
  3323. Var
  3324. {$ifndef Win32}
  3325. Name: string;
  3326. {$endif}
  3327. NewName: string;
  3328. Begin
  3329. {$ifndef Win32}
  3330.   Name := StrPas(aName);
  3331. {$endif}
  3332.   NewName := GetLZMarkedName(Name);
  3333.   LZCompressEx := LZCompress({$ifdef Win32} Name,  NewName,
  3334.                              {$else}        aName, Str2PChar(NewName),
  3335.                              {$endif} ReplaceQuestion, aProc);
  3336. End;
  3337. {/////////////////////////////////////////////////////////}
  3338. {/////////////////////////////////////////////////////////}
  3339. Function LZDecompressEx({$ifdef Win32} Name:  string
  3340.                         {$else}        aName: PChar
  3341.                         {$endif};
  3342.                         ReplaceQuestion:TLZQuestionFunc;
  3343.                         aProc:TLZReportProc): LongInt;
  3344. {$ifdef aDLL} {$ifdef Win32} stdcall
  3345.               {$else Win32}  export
  3346.               {$endif Win32};
  3347. {$endif aDLL}
  3348. Var
  3349. s2:string;
  3350. {$ifndef Win32}
  3351. s:    string;
  3352. Name: string;
  3353. {$endif}
  3354. OutName: {$ifdef Win32} string;
  3355.          {$else}        array[0..79] of Char;
  3356.          {$endif}
  3357. IsHeaderRead: boolean;
  3358.  
  3359. Begin
  3360. {$ifdef Win32}
  3361.   LZDecompressEx := 0;
  3362. {$else}
  3363.   LZDecompressEx := -100;
  3364.   Name := StrPas(aName);
  3365. {$endif}
  3366.  
  3367.   if Length(Name) <> 0 then
  3368.   begin
  3369.  
  3370.   IsHeaderRead := false;
  3371.  
  3372.   {see if source file exists}
  3373.   If Not FileExists(Name) then {look for name ending with MyLZMarker}
  3374.   begin
  3375.    {$ifdef Win32}
  3376.      s2 := Name;
  3377.    {$else}
  3378.      s2 := Uppercase(Name);
  3379.    {$endif}
  3380.      Name := GetLZMarkedName(Name);
  3381. {
  3382.   If Win32, then GetChiefLZFileName() will throw the correct exception when
  3383.   it tries to open Name. No need to do it manually.
  3384. }
  3385.    {$ifndef Win32}
  3386.      if not FileExists(Name) then {source file not found}
  3387.        Exit;
  3388.      aName := Str2PChar(Name);
  3389.    {$endif}
  3390.  
  3391.    {$ifdef Win32}
  3392.      OutName := GetChiefLZFileName(Name);   { read header ... }
  3393.      if AnsiCompareText( ExtractFileName(OutName),
  3394.                          ExtractFileName(s2) ) <> 0 then
  3395.        RaiseErrorStr(EChiefLZCompress,SWrongCompressedFile,OutName)
  3396.    {$else}
  3397.      GetChiefLZFileName(aName, OutName);
  3398.      s := Uppercase(StrPas(OutName));
  3399.      If ExtractFileName(s)<>ExtractFileName(s2) {wrong uncompressed file}
  3400.      then
  3401.        begin
  3402.          LZDecompressEx := -2; {wrong file}
  3403.          Exit
  3404.        end
  3405.    {$endif};
  3406.      IsHeaderRead := True
  3407.   end;
  3408.   {not FileExists}
  3409.  
  3410.   {$ifdef Win32}
  3411.   if not IsHeaderRead then
  3412.     OutName := GetChiefLZFileName(Name);
  3413.  
  3414.   if Length(OutName) > 0 then
  3415.     begin
  3416.      {check for same source and target}
  3417.       OutName := ExtractFileName(OutName);
  3418.       Name := ExpandFileName(Name);
  3419.  
  3420.       if AnsiCompareText(ExtractFileName(Name),OutName) = 0 then
  3421.         RaiseErrorStr(EChiefLZCompress,SSameFileName,Name);
  3422.  
  3423.       Insert(ExtractFilePath(Name),OutName,1);
  3424.       LZDecompressEx := LZDecompress(Name, OutName, ReplaceQuestion, aProc)
  3425.     end
  3426.  
  3427.   {$else Win32}
  3428.  
  3429.   if not IsHeaderRead then
  3430.     GetChiefLZFileName(aName, OutName);
  3431.  
  3432.   if StrLen(OutName) > 0 then begin
  3433.     s  := ExtractFileName(StrPas(OutName)); {get just file name}
  3434.     s2 := ExtractFilePath(Name);       {does source file have path?}
  3435.     If Length(s2) = 0 then
  3436.       GetDir(0, s2);                   {if not, use current directory}
  3437.     s2 := AddBackSlash(s2); {add '\'}
  3438.     Insert(s2,s,1);   {target file}
  3439.  
  3440.     {check for same source and target}
  3441.     If Length(ExtractFilePath(Name)) = 0 then
  3442.       Insert(s2,Name,1);
  3443.  
  3444.     If Uppercase(Name)=Uppercase(s) then
  3445.       LZDecompressEx := -3  {same source & target}
  3446.     else
  3447.       LZDecompressEx := LZDecompress(aName,Str2PChar(s),ReplaceQuestion,aProc)
  3448.   end; { StrLen(OutName) > 0 }
  3449.   {$endif Win32}
  3450.  
  3451.   end; { Length(Name) <> 0 }
  3452. End;
  3453.  
  3454. {////////////////////////////////////////////////////}
  3455. {////////////////////////////////////////////////////}
  3456. {////////////////////////////////////////////////////}
  3457. {///   implementation of LZ object  /////////////////}
  3458. {////////////////////////////////////////////////////}
  3459. {//////  CANNOT BE USED BY .DLL  ////////////////////}
  3460. {////////////////////////////////////////////////////}
  3461. {////////////////////////////////////////////////////}
  3462. {$ifndef aDLL}
  3463. Constructor LZObj.{$ifdef Delphi} Create {$else} Init {$endif};
  3464. Begin
  3465. {$ifndef Win32}   { Delphi 2.0 automatically zeros new objects }
  3466.    ReportProc := Nil;
  3467.    QuestionProc := Nil;
  3468.    {$ifdef Delphi}
  3469.    FInputName[0] := #0;
  3470.    FOutputName[0] := #0;
  3471.    {$else}
  3472.    IsInited := False;
  3473.    InputName[0] := #0;
  3474.    OutputName[0] := #0;
  3475.    {$endif}
  3476. {$endif}
  3477.  
  3478. {$ifdef Delphi}
  3479.  {$ifDef Win32}
  3480.   FInputName := InFName;
  3481.   FOutputName := OutFName;
  3482.  {$else Win32}
  3483.  StrPCopy(FInputName, InFName);
  3484.  StrPCopy(FOutputName, OutFName);
  3485.  {$Endif Win32}
  3486. {$else}
  3487.   SetInputName(InFName);
  3488.   SetOutputName(OutFName);
  3489. {$endif}
  3490. End;
  3491. {////////////////////////////////////////////////////}
  3492. Destructor LZObj.{$ifdef Delphi} Destroy {$else} Done {$endif};
  3493. Begin
  3494. {$ifdef Win32}
  3495.   SetLength(FInputName,0);
  3496.   SetLength(FOutputName,0);
  3497. {$else}
  3498. {$ifdef Delphi}
  3499.    FInputName[0] := #0;
  3500.    FOutputName[0] := #0;
  3501. {$else}
  3502.    IsInited := False;
  3503.    InputName[0] := #0;
  3504.    OutputName[0] := #0;
  3505. {$endif}
  3506. {$endif}
  3507. {$ifdef Delphi}
  3508.    FReportProc := Nil;
  3509.    FQuestionProc := Nil;
  3510. {$else}
  3511.    ReportProc := Nil;
  3512.    QuestionProc := Nil;
  3513. {$endif}
  3514. End;
  3515. {////////////////////////////////////////////////////}
  3516. {$ifdef Delphi}
  3517. Function LZObj.GetIsInited: boolean;
  3518. begin
  3519. {$ifdef Win32}
  3520.   GetIsInited := Length(FInputName) > 0;
  3521. {$else}
  3522.   GetIsInited := StrLen(FInputName) > 0;  
  3523. {$endif}
  3524. end;
  3525. {////////////////////////////////////////////////////}
  3526. {$else}
  3527. Procedure LZObj.SetInputName;
  3528. Begin
  3529.    If Length(aName)>0 then IsInited := True;
  3530.    StrPCopy(InputName, aName);
  3531. End;
  3532. {////////////////////////////////////////////////////}
  3533. Procedure LZObj.SetOutputName;
  3534. Begin
  3535.   StrPCopy(OutputName, aName);
  3536. End;
  3537. {$endif}
  3538. {////////////////////////////////////////////////////}
  3539. Function LZObj.Compress:Longint;
  3540. Begin
  3541.    if not IsInited then
  3542.      Compress := -100
  3543.    else if {$ifdef Win32} Length(FOutputName)
  3544.            {$else}        StrLen(OutputName)
  3545.            {$endif} > 0 then
  3546.      Compress := LZCompress(InputName, OutputName, QuestionProc, ReportProc)
  3547.    else
  3548.      Compress := LZCompressEx(InputName, QuestionProc, ReportProc)
  3549. End;
  3550. {////////////////////////////////////////////////////}
  3551. Function LZObj.Decompress:Longint;
  3552. Begin
  3553.    if not IsInited then
  3554.      Decompress := -100
  3555.    else if {$ifdef Win32} Length(FOutputName)
  3556.            {$else}        StrLen(OutputName)
  3557.            {$endif} > 0 then
  3558.      Decompress := LZDeCompress(InputName, OutputName, QuestionProc, ReportProc)
  3559.    else
  3560.      Decompress := LZDeCompressEx(InputName, QuestionProc, ReportProc)
  3561. End;
  3562. {////////////////////////////////////////////////////}
  3563. {$ifndef Delphi}
  3564. Procedure LZObj.SetReportProc;
  3565. Begin
  3566.   ReportProc := aProc;
  3567. End;
  3568. {////////////////////////////////////////////////////}
  3569. Procedure LZObj.SetQuestionProc;
  3570. Begin
  3571.   QuestionProc := aProc;
  3572. End;
  3573. {$endif Delphi}
  3574. {$endif aDLL}
  3575.  
  3576. {/////////////////////////////////////////////////////////}
  3577. {$IFNDEF Win32}
  3578. Function HeapFunc(Size: Word): Integer; far; assembler;
  3579. Asm
  3580.   MOV AX, 1
  3581. End; { HeapFunc }
  3582. {$ENDIF}
  3583.  
  3584. {////////////////////////////////////////////////////}
  3585. {////////////////////////////////////////////////////}
  3586. {////////////////////////////////////////////////////}
  3587. {////////////////////////////////////////////////////}
  3588. {////////////////////////////////////////////////////}
  3589. {$ifdef aDLL}
  3590. {
  3591.   Procedural interface to allow MyLZMarker to be modified if a DLL.
  3592.   Utterly redundant if NOT DLL, since MyLZMarker is published in the
  3593.   interface and we WANT to grant read/write access.
  3594. }
  3595. function GetLZMarkerChar: Char; {$ifdef Win32} stdcall {$else} export {$endif};
  3596. begin
  3597.   GetLZMarkerChar := MyLZMarker
  3598. end;
  3599.  
  3600. procedure SetLZMarkerChar(const NewChar: Char);
  3601. {$ifdef Win32} stdcall {$else} export {$endif};
  3602. begin
  3603.   MyLZMarker := NewChar
  3604. end;
  3605.  
  3606. function ChiefLZDLLVersion: Integer;
  3607. {$ifdef Win32} stdcall {$else} export {$endif Win32};
  3608. begin
  3609.   ChiefLZDLLVersion := ChiefLZVersionNumber
  3610. end;
  3611.  
  3612. Exports
  3613.    LZCompress            index 1  {$ifdef Win32} name 'LZCompress' {$endif},
  3614.    LZDecompress          index 2  {$ifdef Win32} name 'LZDecompress' {$endif},
  3615.    IsChiefLZFile         index 3  {$ifdef Win32} name 'IsChiefLZFile' {$endif},
  3616.    LZArchive             index 4  {$ifdef Win32} name 'LZArchive' {$endif},
  3617.    LZDearchive           index 5  {$ifdef Win32} name 'LZDearchive' {$endif},
  3618.    IsChiefLZArchive      index 6  {$ifdef Win32} name 'IsChiefLZArchive' {$endif},
  3619.    GetChiefLZFileName    index 7  {$ifdef Win32} name 'GetChiefLZFileName' {$endif},
  3620.    GetChiefLZFileSize    index 8  {$ifdef Win32} name 'GetChiefLZFileSize' {$endif},
  3621.    GetChiefLZArchiveInfo index 9  {$ifdef Win32} name 'GetChiefLZArchiveInfo' {$endif},
  3622.    LZCompressEx          index 10 {$ifdef Win32} name 'LZCompressEx' {$endif},
  3623.    LZDeCompressEx        index 11 {$ifdef Win32} name 'LZDecompressEx' {$endif},
  3624.    GetLZMarkerChar       index 12 {$ifdef Win32} name 'GetLZMarkerChar' {$endif},
  3625.    SetLZMarkerChar       index 13 {$ifdef Win32} name 'SetLZMarkerChar' {$endif},
  3626.    GetFullLZName         index 14 {$ifdef Win32} name 'GetFullLZName' {$endif},
  3627.    ChiefLZDLLVersion     index 15 {$ifdef Win32} name 'ChiefLZDLLVersion' {$endif},
  3628.    GetChiefLZArchiveSize index 16 {$ifdef Win32} name 'GetChiefLZArchiveSize' {$endif};
  3629.  
  3630. {$endif aDLL}
  3631.  
  3632. {/////////////////////////////////////////////////////////}
  3633. {/////////////////////////////////////////////////////////}
  3634. {/////////////////////////////////////////////////////////}
  3635. {/////////////////////////////////////////////////////////}
  3636. {$ifdef Win32}
  3637. {
  3638.   Delphi 2.00 does some VERY nasty things to DLLs if:
  3639. (a) You include an initialisation section (even an empty one)
  3640. and
  3641. (b) You declare an uninitialised Global string variable; either
  3642.     on its own or as part of a record.
  3643.  
  3644.   I have therefore tried to work around this by pre-initialising as
  3645.   many of the global variables as possible (in the 32-bit code). Note
  3646.   that BlankRec contains a field called Name, which is a long-string
  3647.   in the Delphi 2 version !!!
  3648. }
  3649. {$ifdef aDLL}
  3650. begin          { <<< Crash And Burn warning !!!! }
  3651. {$else aDLL}   { Must have NO uninitialised global long-string vars!! }
  3652. initialization
  3653. {$endif aDLL}
  3654. {$else Win32}
  3655. Begin
  3656. {
  3657.   These variables can be initialised here in the 16-bit version ...
  3658. }
  3659.   HeapError := @HeapFunc;  { Specific to 16-bit code }
  3660.  
  3661.   FillChar(BlankRec, SizeOf(BlankRec), 0);
  3662.   LZReportProc := Nil;
  3663. {$endif Win32}
  3664.   Decompressing :=False;
  3665. {
  3666.   These variables MUST be initialised here ...
  3667. }
  3668.   LZReadProc  := MyReadProc;
  3669.   LZWriteProc := MyWriteProc
  3670. End.
  3671.  
  3672.